/// <summary> /// Instantiate a sasl client for the first supported auth type in the /// given list. /// </summary> /// <remarks> /// Instantiate a sasl client for the first supported auth type in the /// given list. The auth type must be defined, enabled, and the user /// must possess the required credentials, else the next auth is tried. /// </remarks> /// <param name="authTypes">to attempt in the given order</param> /// <returns>SaslAuth of instantiated client</returns> /// <exception cref="AccessControlException">- client doesn't support any of the auths /// </exception> /// <exception cref="System.IO.IOException">- misc errors</exception> /// <exception cref="Javax.Security.Sasl.SaslException"/> /// <exception cref="Org.Apache.Hadoop.Security.AccessControlException"/> private RpcHeaderProtos.RpcSaslProto.SaslAuth SelectSaslClient(IList <RpcHeaderProtos.RpcSaslProto.SaslAuth > authTypes) { RpcHeaderProtos.RpcSaslProto.SaslAuth selectedAuthType = null; bool switchToSimple = false; foreach (RpcHeaderProtos.RpcSaslProto.SaslAuth authType in authTypes) { if (!IsValidAuthType(authType)) { continue; } // don't know what it is, try next SaslRpcServer.AuthMethod authMethod = SaslRpcServer.AuthMethod.ValueOf(authType.GetMethod ()); if (authMethod == SaslRpcServer.AuthMethod.Simple) { switchToSimple = true; } else { saslClient = CreateSaslClient(authType); if (saslClient == null) { // client lacks credentials, try next continue; } } selectedAuthType = authType; break; } if (saslClient == null && !switchToSimple) { IList <string> serverAuthMethods = new AList <string>(); foreach (RpcHeaderProtos.RpcSaslProto.SaslAuth authType_1 in authTypes) { serverAuthMethods.AddItem(authType_1.GetMethod()); } throw new AccessControlException("Client cannot authenticate via:" + serverAuthMethods ); } if (Log.IsDebugEnabled()) { Log.Debug("Use " + selectedAuthType.GetMethod() + " authentication for protocol " + protocol.Name); } return(selectedAuthType); }
private bool IsValidAuthType(RpcHeaderProtos.RpcSaslProto.SaslAuth authType) { SaslRpcServer.AuthMethod authMethod; try { authMethod = SaslRpcServer.AuthMethod.ValueOf(authType.GetMethod()); } catch (ArgumentException) { // unknown auth authMethod = null; } // do we know what it is? is it using our mechanism? return(authMethod != null && authMethod.GetMechanismName().Equals(authType.GetMechanism ())); }
/// <summary> /// Do client side SASL authentication with server via the given InputStream /// and OutputStream /// </summary> /// <param name="inS">InputStream to use</param> /// <param name="outS">OutputStream to use</param> /// <returns>AuthMethod used to negotiate the connection</returns> /// <exception cref="System.IO.IOException"/> public virtual SaslRpcServer.AuthMethod SaslConnect(InputStream inS, OutputStream outS) { DataInputStream inStream = new DataInputStream(new BufferedInputStream(inS)); DataOutputStream outStream = new DataOutputStream(new BufferedOutputStream(outS)); // redefined if/when a SASL negotiation starts, can be queried if the // negotiation fails authMethod = SaslRpcServer.AuthMethod.Simple; SendSaslMessage(outStream, negotiateRequest); // loop until sasl is complete or a rpc error occurs bool done = false; do { int totalLen = inStream.ReadInt(); ProtobufRpcEngine.RpcResponseMessageWrapper responseWrapper = new ProtobufRpcEngine.RpcResponseMessageWrapper (); responseWrapper.ReadFields(inStream); RpcHeaderProtos.RpcResponseHeaderProto header = responseWrapper.GetMessageHeader( ); switch (header.GetStatus()) { case RpcHeaderProtos.RpcResponseHeaderProto.RpcStatusProto.Error: case RpcHeaderProtos.RpcResponseHeaderProto.RpcStatusProto.Fatal: { // might get a RPC error during throw new RemoteException(header.GetExceptionClassName(), header.GetErrorMsg()); } default: { break; } } if (totalLen != responseWrapper.GetLength()) { throw new SaslException("Received malformed response length"); } if (header.GetCallId() != Server.AuthProtocol.Sasl.callId) { throw new SaslException("Non-SASL response during negotiation"); } RpcHeaderProtos.RpcSaslProto saslMessage = RpcHeaderProtos.RpcSaslProto.ParseFrom (responseWrapper.GetMessageBytes()); if (Log.IsDebugEnabled()) { Log.Debug("Received SASL message " + saslMessage); } // handle sasl negotiation process RpcHeaderProtos.RpcSaslProto.Builder response = null; switch (saslMessage.GetState()) { case RpcHeaderProtos.RpcSaslProto.SaslState.Negotiate: { // create a compatible SASL client, throws if no supported auths RpcHeaderProtos.RpcSaslProto.SaslAuth saslAuthType = SelectSaslClient(saslMessage .GetAuthsList()); // define auth being attempted, caller can query if connect fails authMethod = SaslRpcServer.AuthMethod.ValueOf(saslAuthType.GetMethod()); byte[] responseToken = null; if (authMethod == SaslRpcServer.AuthMethod.Simple) { // switching to SIMPLE done = true; } else { // not going to wait for success ack byte[] challengeToken = null; if (saslAuthType.HasChallenge()) { // server provided the first challenge challengeToken = saslAuthType.GetChallenge().ToByteArray(); saslAuthType = ((RpcHeaderProtos.RpcSaslProto.SaslAuth)RpcHeaderProtos.RpcSaslProto.SaslAuth .NewBuilder(saslAuthType).ClearChallenge().Build()); } else { if (saslClient.HasInitialResponse()) { challengeToken = new byte[0]; } } responseToken = (challengeToken != null) ? saslClient.EvaluateChallenge(challengeToken ) : new byte[0]; } response = CreateSaslReply(RpcHeaderProtos.RpcSaslProto.SaslState.Initiate, responseToken ); response.AddAuths(saslAuthType); break; } case RpcHeaderProtos.RpcSaslProto.SaslState.Challenge: { if (saslClient == null) { // should probably instantiate a client to allow a server to // demand a specific negotiation throw new SaslException("Server sent unsolicited challenge"); } byte[] responseToken = SaslEvaluateToken(saslMessage, false); response = CreateSaslReply(RpcHeaderProtos.RpcSaslProto.SaslState.Response, responseToken ); break; } case RpcHeaderProtos.RpcSaslProto.SaslState.Success: { // simple server sends immediate success to a SASL client for // switch to simple if (saslClient == null) { authMethod = SaslRpcServer.AuthMethod.Simple; } else { SaslEvaluateToken(saslMessage, true); } done = true; break; } default: { throw new SaslException("RPC client doesn't support SASL " + saslMessage.GetState ()); } } if (response != null) { SendSaslMessage(outStream, ((RpcHeaderProtos.RpcSaslProto)response.Build())); } }while (!done); return(authMethod); }
/// <summary>Try to create a SaslClient for an authentication type.</summary> /// <remarks> /// Try to create a SaslClient for an authentication type. May return /// null if the type isn't supported or the client lacks the required /// credentials. /// </remarks> /// <param name="authType">- the requested authentication method</param> /// <returns>SaslClient for the authType or null</returns> /// <exception cref="Javax.Security.Sasl.SaslException">- error instantiating client</exception> /// <exception cref="System.IO.IOException">- misc errors</exception> private SaslClient CreateSaslClient(RpcHeaderProtos.RpcSaslProto.SaslAuth authType ) { string saslUser = null; // SASL requires the client and server to use the same proto and serverId // if necessary, auth types below will verify they are valid string saslProtocol = authType.GetProtocol(); string saslServerName = authType.GetServerId(); IDictionary <string, string> saslProperties = saslPropsResolver.GetClientProperties (serverAddr.Address); CallbackHandler saslCallback = null; SaslRpcServer.AuthMethod method = SaslRpcServer.AuthMethod.ValueOf(authType.GetMethod ()); switch (method) { case SaslRpcServer.AuthMethod.Token: { Org.Apache.Hadoop.Security.Token.Token <object> token = GetServerToken(authType); if (token == null) { return(null); } // tokens aren't supported or user doesn't have one saslCallback = new SaslRpcClient.SaslClientCallbackHandler(token); break; } case SaslRpcServer.AuthMethod.Kerberos: { if (ugi.GetRealAuthenticationMethod().GetAuthMethod() != SaslRpcServer.AuthMethod .Kerberos) { return(null); } // client isn't using kerberos string serverPrincipal = GetServerPrincipal(authType); if (serverPrincipal == null) { return(null); } // protocol doesn't use kerberos if (Log.IsDebugEnabled()) { Log.Debug("RPC Server's Kerberos principal name for protocol=" + protocol.GetCanonicalName () + " is " + serverPrincipal); } break; } default: { throw new IOException("Unknown authentication method " + method); } } string mechanism = method.GetMechanismName(); if (Log.IsDebugEnabled()) { Log.Debug("Creating SASL " + mechanism + "(" + method + ") " + " client to authenticate to service at " + saslServerName); } return(Javax.Security.Sasl.Sasl.CreateSaslClient(new string[] { mechanism }, saslUser , saslProtocol, saslServerName, saslProperties, saslCallback)); }