private void saslReadAndProcess(DataInputStream dis) throws WrappedRpcServerException, IOException, InterruptedException { final RpcSaslProto saslMessage = decodeProtobufFromStream(RpcSaslProto.newBuilder(), dis); switch (saslMessage.getState()) { case WRAP: { if (!saslContextEstablished || !useWrap) { throw new WrappedRpcServerException( RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER, new SaslException("Server is not wrapping data")); } // loops over decoded data and calls processOneRpc unwrapPacketAndProcessRpcs(saslMessage.getToken().toByteArray()); break; } default: saslProcess(saslMessage); } }
/** * Evaluate the server provided challenge. The server must send a token * if it's not done. If the server is done, the challenge token is * optional because not all mechanisms send a final token for the client to * update its internal state. The client must also be done after * evaluating the optional token to ensure a malicious server doesn't * prematurely end the negotiation with a phony success. * * @param saslResponse - client response to challenge * @param serverIsDone - server negotiation state * @throws SaslException - any problems with negotiation */ private byte[] saslEvaluateToken(RpcSaslProto saslResponse, boolean serverIsDone) throws SaslException { byte[] saslToken = null; if (saslResponse.hasToken()) { saslToken = saslResponse.getToken().toByteArray(); saslToken = saslClient.evaluateChallenge(saslToken); } else if (!serverIsDone) { // the server may only omit a token when it's done throw new SaslException("Server challenge contains no token"); } if (serverIsDone) { // server tried to report success before our client completed if (!saslClient.isComplete()) { throw new SaslException("Client is out of sync with server"); } // a client cannot generate a response to a success message if (saslToken != null) { throw new SaslException("Client generated spurious response"); } } return saslToken; }
/** * Process the Sasl's Negotiate request, including the optimization of * accelerating token negotiation. * @return the response to Negotiate request - the list of enabled * authMethods and challenge if the TOKENS are supported. * @throws SaslException - if attempt to generate challenge fails. * @throws IOException - if it fails to create the SASL server for Tokens */ private RpcSaslProto buildSaslNegotiateResponse() throws InterruptedException, SaslException, IOException { RpcSaslProto negotiateMessage = negotiateResponse; // accelerate token negotiation by sending initial challenge // in the negotiation response if (enabledAuthMethods.contains(AuthMethod.TOKEN)) { saslServer = createSaslServer(AuthMethod.TOKEN); byte[] challenge = saslServer.evaluateResponse(new byte[0]); RpcSaslProto.Builder negotiateBuilder = RpcSaslProto.newBuilder(negotiateResponse); negotiateBuilder.getAuthsBuilder(0) // TOKEN is always first .setChallenge(ByteString.copyFrom(challenge)); negotiateMessage = negotiateBuilder.build(); } sentNegotiate = true; return negotiateMessage; }
public void initialize() throws SaslException { // init quorum auth server & learner if (isQuorumSaslAuthEnabled()) { Set<String> authzHosts = new HashSet<String>(); for (QuorumServer qs : getView().values()) { authzHosts.add(qs.hostname); } authServer = new SaslQuorumAuthServer(isQuorumServerSaslAuthRequired(), quorumServerLoginContext, authzHosts); authLearner = new SaslQuorumAuthLearner(isQuorumLearnerSaslAuthRequired(), quorumServicePrincipal, quorumLearnerLoginContext); authInitialized = true; } else { authServer = new NullQuorumAuthServer(); authLearner = new NullQuorumAuthLearner(); } }
private void sendSaslPacket(byte[] saslToken, ClientCnxn cnxn) throws SaslException{ if (LOG.isDebugEnabled()) { LOG.debug("ClientCnxn:sendSaslPacket:length="+saslToken.length); } GetSASLRequest request = new GetSASLRequest(); request.setToken(saslToken); SetSASLResponse response = new SetSASLResponse(); ServerSaslResponseCallback cb = new ServerSaslResponseCallback(); try { cnxn.sendPacket(request,response,cb, ZooDefs.OpCode.sasl); } catch (IOException e) { throw new SaslException("Failed to send SASL packet to server.", e); } }
@Override public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, String serverName, Map<String, ?> props, CallbackHandler cbh) throws SaslException { ScramMechanism mechanism = null; for (String mech : mechanisms) { mechanism = ScramMechanism.forMechanismName(mech); if (mechanism != null) break; } if (mechanism == null) throw new SaslException(String.format("Requested mechanisms '%s' not supported. Supported mechanisms are '%s'.", Arrays.asList(mechanisms), ScramMechanism.mechanismNames())); try { return new ScramSaslClient(mechanism, cbh); } catch (NoSuchAlgorithmException e) { throw new SaslException("Hash algorithm not supported for mechanism " + mechanism, e); } }
private void processConnection(SaslEndpoint endpoint) throws SaslException, IOException, ClassNotFoundException { System.out.println("process connection"); endpoint.send(SUPPORT_MECHS); Object o = endpoint.receive(); if (!(o instanceof String)) { throw new RuntimeException("Received unexpected object: " + o); } String mech = (String) o; SaslServer saslServer = createSaslServer(mech); Message msg = getMessage(endpoint.receive()); while (!saslServer.isComplete()) { byte[] data = processData(msg.getData(), endpoint, saslServer); if (saslServer.isComplete()) { System.out.println("server is complete"); endpoint.send(new Message(SaslStatus.SUCCESS, data)); } else { System.out.println("server continues"); endpoint.send(new Message(SaslStatus.CONTINUE, data)); msg = getMessage(endpoint.receive()); } } }
public SaslQuorumAuthServer(boolean quorumRequireSasl, String loginContext, Set<String> authzHosts) throws SaslException { this.quorumRequireSasl = quorumRequireSasl; try { AppConfigurationEntry entries[] = Configuration.getConfiguration() .getAppConfigurationEntry(loginContext); if (entries == null || entries.length == 0) { throw new LoginException("SASL-authentication failed" + " because the specified JAAS configuration " + "section '" + loginContext + "' could not be found."); } SaslQuorumServerCallbackHandler saslServerCallbackHandler = new SaslQuorumServerCallbackHandler( Configuration.getConfiguration(), loginContext, authzHosts); serverLogin = new Login(loginContext, saslServerCallbackHandler); serverLogin.startThreadIfNeeded(); } catch (Throwable e) { throw new SaslException( "Failed to initialize authentication mechanism using SASL", e); } }
SaslInputStream(SaslClient sc, InputStream in) throws SaslException { super(); this.in = in; this.sc = sc; String str = (String) sc.getNegotiatedProperty(Sasl.MAX_BUFFER); if (str != null) { try { recvMaxBufSize = Integer.parseInt(str); } catch (NumberFormatException e) { throw new SaslException(Sasl.MAX_BUFFER + " property must be numeric string: " + str); } } saslBuffer = new byte[recvMaxBufSize]; }
/** * SaslQuorumAuthServer throws exception on receiving an invalid quorum * auth packet. */ @Test(timeout = 30000) public void testSaslQuorumAuthServerWithInvalidQuorumAuthPacket() throws Exception { Socket socket = getSocketPair(); DataOutputStream dout = new DataOutputStream(socket.getOutputStream()); BufferedOutputStream bufferedOutput = new BufferedOutputStream(dout); BinaryOutputArchive boa = BinaryOutputArchive .getArchive(bufferedOutput); QuorumAuthPacket authPacket = QuorumAuth .createPacket(QuorumAuth.Status.IN_PROGRESS, null); authPacket.setMagic(Long.MAX_VALUE); // invalid magic number boa.writeRecord(authPacket, null); bufferedOutput.flush(); QuorumAuthServer authServer = new SaslQuorumAuthServer(true, "QuorumServer", authzHosts); BufferedInputStream is = new BufferedInputStream( socket.getInputStream()); try { authServer.authenticate(socket, new DataInputStream(is)); Assert.fail("Must throw exception as QuorumAuthPacket is invalid"); } catch (SaslException e) { // expected } }
public void initialize(ClientCnxn cnxn) throws SaslException { if (saslClient == null) { saslState = SaslState.FAILED; throw new SaslException("saslClient failed to initialize properly: it's null."); } if (saslState == SaslState.INITIAL) { if (saslClient.hasInitialResponse()) { sendSaslPacket(cnxn); } else { byte[] emptyToken = new byte[0]; sendSaslPacket(emptyToken, cnxn); } saslState = SaslState.INTERMEDIATE; } }
public SampleServer(String supportedQOPs) throws SaslException { Map<String,String> properties = new HashMap<String,String>(); if (supportedQOPs != null) { properties.put(Sasl.QOP, supportedQOPs); } saslServer = Sasl.createSaslServer(DIGEST_MD5, "local", "127.0.0.1", properties, new SampleCallbackHandler()); }
/** Release resources used by wrapped saslClient */ public void dispose() throws SaslException { if (saslClient != null) { saslClient.dispose(); saslClient = null; } }
/** * Disposes of any system resources or security-sensitive information Sasl * might be using. * * @exception SaslException * if a SASL error occurs. */ private void disposeSasl() throws SaslException { if (saslClient != null) { saslClient.dispose(); } if (saslServer != null) { saslServer.dispose(); } }
/** * Writes <code>len</code> bytes from the specified byte array starting at * offset <code>off</code> to this output stream. * * @param inBuf * the data. * @param off * the start offset in the data. * @param len * the number of bytes to write. * @exception IOException * if an I/O error occurs. */ @Override public void write(byte[] inBuf, int off, int len) throws IOException { if (!useWrap) { outStream.write(inBuf, off, len); return; } try { if (saslServer != null) { // using saslServer saslToken = saslServer.wrap(inBuf, off, len); } else { // using saslClient saslToken = saslClient.wrap(inBuf, off, len); } } catch (SaslException se) { try { disposeSasl(); } catch (SaslException ignored) { } throw se; } if (saslToken != null) { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); DataOutputStream dout = new DataOutputStream(byteOut); dout.writeInt(saslToken.length); outStream.write(byteOut.toByteArray()); outStream.write(saslToken, 0, saslToken.length); saslToken = null; } }
public void negotiate(SampleServer server) throws SaslException { byte[] challenge; byte[] response; response = (saslClient.hasInitialResponse () ? saslClient.evaluateChallenge (new byte [0]) : new byte [0]); while (! saslClient.isComplete()) { challenge = server.evaluate(response); response = saslClient.evaluateChallenge(challenge); } }
/** * Read more data and get them processed <br> * Entry condition: ostart = ofinish <br> * Exit condition: ostart <= ofinish <br> * * return (ofinish-ostart) (we have this many bytes for you), 0 (no data now, * but could have more later), or -1 (absolutely no more data) */ private int readMoreData() throws IOException { try { inStream.readFully(lengthBuf); int length = unsignedBytesToInt(lengthBuf); if (LOG.isDebugEnabled()) LOG.debug("Actual length is " + length); saslToken = new byte[length]; inStream.readFully(saslToken); } catch (EOFException e) { return -1; } try { if (saslServer != null) { // using saslServer obuffer = saslServer.unwrap(saslToken, 0, saslToken.length); } else { // using saslClient obuffer = saslClient.unwrap(saslToken, 0, saslToken.length); } } catch (SaslException se) { try { disposeSasl(); } catch (SaslException ignored) { } throw se; } ostart = 0; if (obuffer == null) ofinish = 0; else ofinish = obuffer.length; return ofinish; }
private void checkAuthStatus(Socket sock, QuorumAuth.Status qpStatus) throws SaslException { if (qpStatus == QuorumAuth.Status.SUCCESS) { LOG.info("Successfully completed the authentication using SASL. server addr: {}, status: {}", sock.getRemoteSocketAddress(), qpStatus); } else { throw new SaslException("Authentication failed against server addr: " + sock.getRemoteSocketAddress() + ", qpStatus: " + qpStatus); } }
public void close() throws IOException { SaslException save = null; try { sc.dispose(); // Dispose of SaslClient's state } catch (SaslException e) { // Save exception for throwing after closing 'in' save = e; } in.close(); // Close underlying input stream if (save != null) { throw save; } }
/** * Wraps the outgoing buffer. CRAM-MD5 supports no security layer. * * @throws SaslException If attempt to use this method. */ public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException { if (completed) { throw new IllegalStateException( "CRAM-MD5 supports neither integrity nor privacy"); } else { throw new IllegalStateException( "CRAM-MD5 authentication not completed"); } }
/** * Unwraps the incoming buffer. CRAM-MD5 supports no security layer. * * @throws SaslException If attempt to use this method. */ public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException { if (completed) { throw new IllegalStateException( "CRAM-MD5 supports neither integrity nor privacy"); } else { throw new IllegalStateException( "CRAM-MD5 authentication not completed"); } }
private void disposeSasl() { if (saslServer != null) { try { saslServer.dispose(); } catch (SaslException ignored) { } } }
private <T extends AbstractScramMessage> void checkInvalidScramMessage(Class<T> clazz, String message) { try { createScramMessage(clazz, message); fail("Exception not throws for invalid message of type " + clazz + " : " + message); } catch (SaslException e) { // Expected exception } }
@Test(expectedExceptions = SaslException.class, expectedExceptionsMessageRegExp = ".*Error while authenticate user with login module.*") public void testEvaluateInvalidPassword() throws Exception { plainSaslServer.evaluateResponse(new byte[] { (byte) 'a', (byte) 0, (byte) 'u', (byte) 's', (byte) 'e', (byte) 'r', (byte) 0, (byte) 'P', (byte) 'a', (byte) 's', (byte) 's' }); Assert.assertEquals(plainSaslServer.isComplete(), false, "Sasl mechanism should not be completed for invalid " + "password."); }
@Test(expectedExceptions = SaslException.class, expectedExceptionsMessageRegExp = ".*Error while authenticate user with login module.*") public void testInvalidCallbackHandler() throws Exception { final PlainSaslCallbackHandler handler = Mockito.mock(PlainSaslCallbackHandler.class); Mockito.doThrow(UnsupportedCallbackException.class).when(handler).handle(Mockito.any()); plainSaslServer = new PlainSaslServer(handler); plainSaslServer.evaluateResponse(new byte[] { (byte) 'a', (byte) 0, (byte) 'u', (byte) 's', (byte) 'e', (byte) 'r', (byte) 0, (byte) 'P', (byte) 'a', (byte) 's', (byte) 's' }); Assert.assertEquals(plainSaslServer.isComplete(), false, "Sasl mechanism should not be completed for invalid " + "password."); }
@Override public void handle(ChannelHandlerContext ctx, AmqpConnectionHandler connectionHandler) { ctx.fireChannelRead((BlockingTask) () -> { Broker broker = connectionHandler.getBroker(); SaslServer saslServer; SaslServerBuilder saslServerBuilder = broker.getAuthenticationManager().getSaslMechanisms() .get(mechanism.toString()); try { if (saslServerBuilder != null) { saslServer = Sasl.createSaslServer(mechanism.toString(), AmqConstant.AMQP_PROTOCOL_IDENTIFIER, connectionHandler.getConfiguration().getHostName(), saslServerBuilder.getProperties(), saslServerBuilder.getCallbackHandler()); connectionHandler.setSaslServer(saslServer); } else { throw new SaslException("Server does not support for mechanism: " + mechanism); } if (saslServer != null) { byte[] challenge = saslServer.evaluateResponse(response.getBytes()); if (saslServer.isComplete()) { ctx.writeAndFlush(new ConnectionTune(256, 65535, 0)); } else { ctx.writeAndFlush(new ConnectionSecure(getChannel(), LongString.parse(challenge))); } } else { throw new SaslException("Sasl server cannot be found for mechanism: " + mechanism); } } catch (SaslException e) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Exception occurred while authenticating incoming connection ", e); } String replyText = "Authentication Failed"; ctx.writeAndFlush(new ConnectionClose(403, ShortString.parseString(replyText), 10, 11)); } }); }
public void close() throws IOException { SaslException save = null; try { sc.dispose(); // Dispose of SaslClient's state } catch (SaslException e) { // Save exception for throwing after closing 'in' save = e; } super.close(); // Close underlying output stream if (save != null) { throw save; } }
public SampleClient(String requestedQOPs) throws SaslException { Map<String,String> properties = new HashMap<String,String>(); if (requestedQOPs != null) { properties.put(Sasl.QOP, requestedQOPs); } saslClient = Sasl.createSaslClient(new String[]{ DIGEST_MD5 }, null, "local", "127.0.0.1", properties, new SampleCallbackHandler()); }
private void sendSaslPacket(ClientCnxn cnxn) throws SaslException { if (LOG.isDebugEnabled()) { LOG.debug("ClientCnxn:sendSaslPacket:length="+saslToken.length); } GetSASLRequest request = new GetSASLRequest(); request.setToken(createSaslToken()); SetSASLResponse response = new SetSASLResponse(); ServerSaslResponseCallback cb = new ServerSaslResponseCallback(); try { cnxn.sendPacket(request,response,cb, ZooDefs.OpCode.sasl); } catch (IOException e) { throw new SaslException("Failed to send SASL packet to server due " + "to IOException:", e); } }
static SaslClient createSaslClient(final String user, final String hostName) throws SaslException { Map<String, Object> saslClientProperties = new HashMap<String, Object>(); saslClientProperties.put(Sasl.MAX_BUFFER, "0"); saslClientProperties.put(Sasl.CREDENTIALS, getGSSCredential(user)); return Sasl.createSaslClient(new String[]{"GSSAPI"}, user, SERVICE_NAME_DEFAULT_VALUE, hostName, saslClientProperties, null); }
private static GSSCredential getGSSCredential(final String userName) throws SaslException { try { Oid krb5Mechanism = new Oid(GSSAPI_OID); GSSManager manager = GSSManager.getInstance(); GSSName name = manager.createName(userName, GSSName.NT_USER_NAME); return manager.createCredential(name, GSSCredential.INDEFINITE_LIFETIME, krb5Mechanism, GSSCredential.INITIATE_ONLY); } catch (GSSException e) { throw new SaslException("Unable to create GSSAPI credential", e); } }
private CheckNegotiatedQOPs(int caseNumber, String requestedQOPs, String supportedQOPs) throws SaslException { this.caseNumber = caseNumber; this.requestedQOPs = requestedQOPs; this.supportedQOPs = supportedQOPs; this.client = new SampleClient(requestedQOPs); this.server = new SampleServer(supportedQOPs); }
private byte[] computeClientFirstMessage() throws SaslException { String userName = "n=" + prepUserName(user); this.rPrefix = randomStringGenerator.generate(RANDOM_LENGTH); String nonce = "r=" + this.rPrefix; this.clientFirstMessageBare = userName + "," + nonce; String clientFirstMessage = GS2_HEADER + this.clientFirstMessageBare; return decodeUTF8(clientFirstMessage); }
private static boolean runTest(String authId, String mech, String[] clientQops, String[] serverQops, boolean expectException) throws Exception { System.out.println("AuthId:" + authId + " mechanism:" + mech + " clientQops: " + Arrays.toString(clientQops) + " serverQops: " + Arrays.toString(serverQops) + " expect exception:" + expectException); try (Server server = Server.start(LOCALHOST, authId, serverQops)) { new Client(LOCALHOST, server.getPort(), mech, authId, clientQops) .run(); if (expectException) { System.out.println("Expected exception not thrown"); return false; } } catch (SaslException e) { if (!expectException) { System.out.println("Unexpected exception: " + e); return false; } System.out.println("Expected exception: " + e); } return true; }
private String encodeUTF8(final byte[] bytes) throws SaslException { try { return new String(bytes, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new SaslException("UTF-8 is not a supported encoding.", e); } }