private User getAuthorizedUgi(String authorizedId) throws IOException { if (authMethod == AuthMethod.DIGEST) { TokenIdentifier tokenId = HBaseSaslRpcServer.getIdentifier(authorizedId, secretManager); UserGroupInformation ugi = tokenId.getUser(); if (ugi == null) { throw new AccessControlException( "Can't retrieve username from tokenIdentifier."); } ugi.addTokenIdentifier(tokenId); return userProvider.create(ugi); } else { return userProvider.create(UserGroupInformation.createRemoteUser(authorizedId)); } }
private User getAuthorizedUgi(String authorizedId) throws IOException { if (authMethod == AuthMethod.DIGEST) { TokenIdentifier tokenId = HBaseSaslRpcServer.getIdentifier(authorizedId, secretManager); UserGroupInformation ugi = tokenId.getUser(); if (ugi == null) { throw new AccessControlException( "Can't retrieve username from tokenIdentifier."); } ugi.addTokenIdentifier(tokenId); return User.create(ugi); } else { return User.create(UserGroupInformation.createRemoteUser(authorizedId)); } }
private UserInformation getUserInfoPB(UserGroupInformation ugi) { if (ugi == null || authMethod == AuthMethod.DIGEST) { // Don't send user for token auth return null; } UserInformation.Builder userInfoPB = UserInformation.newBuilder(); if (authMethod == AuthMethod.KERBEROS) { // Send effective user for Kerberos auth userInfoPB.setEffectiveUser(ugi.getUserName()); } else if (authMethod == AuthMethod.SIMPLE) { //Send both effective user and real user for simple auth userInfoPB.setEffectiveUser(ugi.getUserName()); if (ugi.getRealUser() != null) { userInfoPB.setRealUser(ugi.getRealUser().getUserName()); } } return userInfoPB.build(); }
private UserGroupInformation getAuthorizedUgi(String authorizedId) throws IOException { if (authMethod == AuthMethod.DIGEST) { TokenIdentifier tokenId = HBaseSaslRpcServer.getIdentifier(authorizedId, secretManager); UserGroupInformation ugi = tokenId.getUser(); if (ugi == null) { throw new AccessControlException( "Can't retrieve username from tokenIdentifier."); } ugi.addTokenIdentifier(tokenId); return ugi; } else { return UserGroupInformation.createRemoteUser(authorizedId); } }
private boolean authorizeConnection() throws IOException { try { // If auth method is DIGEST, the token was obtained by the // real user for the effective user, therefore not required to // authorize real user. doAs is allowed only for simple or kerberos // authentication if (user != null && user.getRealUser() != null && (authMethod != AuthMethod.DIGEST)) { ProxyUsers.authorize(user, this.getHostAddress(), conf); } authorize(user, header, getHostInetAddress()); if (LOG.isDebugEnabled()) { LOG.debug("Successfully authorized " + header); } metrics.authorizationSuccess(); } catch (AuthorizationException ae) { LOG.debug("Connection authorization failed: "+ae.getMessage(), ae); metrics.authorizationFailure(); setupResponse(authFailedResponse, authFailedCall, Status.FATAL, ae.getClass().getName(), ae.getMessage()); responder.doRespond(authFailedCall); return false; } return true; }
private synchronized boolean shouldAuthenticateOverKrb() throws IOException { UserGroupInformation loginUser = UserGroupInformation.getLoginUser(); UserGroupInformation currentUser = UserGroupInformation.getCurrentUser(); UserGroupInformation realUser = currentUser.getRealUser(); return authMethod == AuthMethod.KERBEROS && loginUser != null && //Make sure user logged in using Kerberos either keytab or TGT loginUser.hasKerberosCredentials() && // relogin only in case it is the login user (e.g. JT) // or superuser (like oozie). (loginUser.equals(currentUser) || loginUser.equals(realUser)); }
@Override public void write(DataOutput out) throws IOException { Text.writeString(out, (protocol == null) ? "" : protocol); if (user != null) { UserGroupInformation ugi = user.getUGI(); if (authMethod == AuthMethod.KERBEROS) { // Send effective user for Kerberos auth out.writeBoolean(true); out.writeUTF(ugi.getUserName()); out.writeBoolean(false); } else if (authMethod == AuthMethod.DIGEST) { // Don't send user for token auth out.writeBoolean(false); } else { //Send both effective user and real user for simple auth out.writeBoolean(true); out.writeUTF(ugi.getUserName()); if (ugi.getRealUser() != null) { out.writeBoolean(true); out.writeUTF(ugi.getRealUser().getUserName()); } else { out.writeBoolean(false); } } } else { out.writeBoolean(false); } }
private boolean authorizeConnection() throws IOException { try { // If auth method is DIGEST, the token was obtained by the // real user for the effective user, therefore not required to // authorize real user. doAs is allowed only for simple or kerberos // authentication if (ticket != null && ticket.getUGI().getRealUser() != null && (authMethod != AuthMethod.DIGEST)) { ProxyUsers.authorize(ticket.getUGI(), this.getHostAddress(), conf); } authorize(ticket, header, getHostInetAddress()); if (LOG.isDebugEnabled()) { LOG.debug("Successfully authorized " + header); } rpcMetrics.authorizationSuccesses.inc(); } catch (AuthorizationException ae) { if (LOG.isDebugEnabled()) { LOG.debug("Connection authorization failed: "+ae.getMessage(), ae); } rpcMetrics.authorizationFailures.inc(); SecureCall failedCall = new SecureCall(AUTHORIZATION_FAILED_CALLID, null, this, null, 0); failedCall.setResponse(null, Status.FATAL, ae.getClass().getName(), ae.getMessage()); responder.doRespond(failedCall); return false; } return true; }
/** * Create a HBaseSaslRpcClient for an authentication method * * @param method * the requested authentication method * @param token * token to use if needed by the authentication method */ public HBaseSaslRpcClient(AuthMethod method, Token<? extends TokenIdentifier> token, String serverPrincipal) throws IOException { switch (method) { case DIGEST: if (LOG.isDebugEnabled()) LOG.debug("Creating SASL " + AuthMethod.DIGEST.getMechanismName() + " client to authenticate to service at " + token.getService()); saslClient = Sasl.createSaslClient(new String[] { AuthMethod.DIGEST .getMechanismName() }, null, null, HBaseSaslRpcServer.SASL_DEFAULT_REALM, HBaseSaslRpcServer.SASL_PROPS, new SaslClientCallbackHandler(token)); break; case KERBEROS: if (LOG.isDebugEnabled()) { LOG .debug("Creating SASL " + AuthMethod.KERBEROS.getMechanismName() + " client. Server's Kerberos principal name is " + serverPrincipal); } if (serverPrincipal == null || serverPrincipal.length() == 0) { throw new IOException( "Failed to specify server's Kerberos principal name"); } String names[] = HBaseSaslRpcServer.splitKerberosName(serverPrincipal); if (names.length != 3) { throw new IOException( "Kerberos principal name does NOT have the expected hostname part: " + serverPrincipal); } saslClient = Sasl.createSaslClient(new String[] { AuthMethod.KERBEROS .getMechanismName() }, null, names[0], names[1], HBaseSaslRpcServer.SASL_PROPS, null); break; default: throw new IOException("Unknown authentication method " + method); } if (saslClient == null) throw new IOException("Unable to find SASL client implementation"); }
/** * Create a HBaseSaslRpcClient for an authentication method * * @param method * the requested authentication method * @param token * token to use if needed by the authentication method */ public HBaseSaslRpcClient(AuthMethod method, Token<? extends TokenIdentifier> token, String serverPrincipal) throws IOException { switch (method) { case DIGEST: if (LOG.isDebugEnabled()) LOG.debug("Creating SASL " + AuthMethod.DIGEST.getMechanismName() + " client to authenticate to service at " + token.getService()); saslClient = Sasl.createSaslClient(new String[] { AuthMethod.DIGEST .getMechanismName() }, null, null, HBaseSaslRpcServer.SASL_DEFAULT_REALM, HBaseSaslRpcServer.SASL_PROPS, new SaslClientCallbackHandler(token)); break; case KERBEROS: if (LOG.isDebugEnabled()) { LOG .debug("Creating SASL " + AuthMethod.KERBEROS.getMechanismName() + " client. Server's Kerberos principal name is " + serverPrincipal); } if (serverPrincipal == null || serverPrincipal.length() == 0) { throw new IOException( "Failed to specify server's Kerberos principal name"); } String names[] = HBaseSaslRpcServer.splitKerberosName(serverPrincipal); if (names.length != 3) { throw new IOException( "Kerberos principal does not have the expected format: " + serverPrincipal); } saslClient = Sasl.createSaslClient(new String[] { AuthMethod.KERBEROS .getMechanismName() }, null, names[0], names[1], HBaseSaslRpcServer.SASL_PROPS, null); break; default: throw new IOException("Unknown authentication method " + method); } if (saslClient == null) throw new IOException("Unable to find SASL client implementation"); }
/** * Create a HBaseSaslRpcClient for an authentication method * * @param method * the requested authentication method * @param token * token to use if needed by the authentication method */ public HBaseSaslRpcClient(AuthMethod method, Token<? extends TokenIdentifier> token, String serverPrincipal, boolean fallbackAllowed) throws IOException { this.fallbackAllowed = fallbackAllowed; switch (method) { case DIGEST: if (LOG.isDebugEnabled()) LOG.debug("Creating SASL " + AuthMethod.DIGEST.getMechanismName() + " client to authenticate to service at " + token.getService()); saslClient = Sasl.createSaslClient(new String[] { AuthMethod.DIGEST .getMechanismName() }, null, null, HBaseSaslRpcServer.SASL_DEFAULT_REALM, HBaseSaslRpcServer.SASL_PROPS, new SaslClientCallbackHandler(token)); break; case KERBEROS: if (LOG.isDebugEnabled()) { LOG .debug("Creating SASL " + AuthMethod.KERBEROS.getMechanismName() + " client. Server's Kerberos principal name is " + serverPrincipal); } if (serverPrincipal == null || serverPrincipal.length() == 0) { throw new IOException( "Failed to specify server's Kerberos principal name"); } String names[] = HBaseSaslRpcServer.splitKerberosName(serverPrincipal); if (names.length != 3) { throw new IOException( "Kerberos principal name does NOT have the expected hostname part: " + serverPrincipal); } saslClient = Sasl.createSaslClient(new String[] { AuthMethod.KERBEROS .getMechanismName() }, null, names[0], names[1], HBaseSaslRpcServer.SASL_PROPS, null); break; default: throw new IOException("Unknown authentication method " + method); } if (saslClient == null) throw new IOException("Unable to find SASL client implementation"); }
public SecureConnection(ConnectionId remoteId) throws IOException { super(remoteId); this.server = remoteId.getAddress(); User ticket = remoteId.getTicket(); Class<?> protocol = remoteId.getProtocol(); this.useSasl = userProvider.isHBaseSecurityEnabled(); if (useSasl && protocol != null) { TokenInfo tokenInfo = protocol.getAnnotation(TokenInfo.class); if (tokenInfo != null) { TokenSelector<? extends TokenIdentifier> tokenSelector = tokenHandlers.get(tokenInfo.value()); if (tokenSelector != null) { token = tokenSelector.selectToken(new Text(clusterId), ticket.getUGI().getTokens()); } else if (LOG.isDebugEnabled()) { LOG.debug("No token selector found for type "+tokenInfo.value()); } } KerberosInfo krbInfo = protocol.getAnnotation(KerberosInfo.class); if (krbInfo != null) { String serverKey = krbInfo.serverPrincipal(); if (serverKey == null) { throw new IOException( "Can't obtain server Kerberos config key from KerberosInfo"); } serverPrincipal = SecurityUtil.getServerPrincipal( conf.get(serverKey), server.getAddress().getCanonicalHostName().toLowerCase()); if (LOG.isDebugEnabled()) { LOG.debug("RPC Server Kerberos principal name for protocol=" + protocol.getCanonicalName() + " is " + serverPrincipal); } } } if (!useSasl) { authMethod = AuthMethod.SIMPLE; } else if (token != null) { authMethod = AuthMethod.DIGEST; } else { authMethod = AuthMethod.KERBEROS; } header = new SecureConnectionHeader( protocol == null ? null : protocol.getName(), ticket, authMethod); if (LOG.isDebugEnabled()) LOG.debug("Use " + authMethod + " authentication for protocol " + protocol.getSimpleName()); reloginMaxBackoff = conf.getInt("hbase.security.relogin.maxbackoff", 5000); }
@Override protected synchronized void setupIOstreams() throws IOException, InterruptedException { if (socket != null || shouldCloseConnection.get()) { return; } try { if (LOG.isDebugEnabled()) { LOG.debug("Connecting to "+server); } short numRetries = 0; final short MAX_RETRIES = 5; Random rand = null; while (true) { setupConnection(); InputStream inStream = NetUtils.getInputStream(socket); OutputStream outStream = NetUtils.getOutputStream(socket, pingInterval); writeRpcHeader(outStream); if (useSasl) { final InputStream in2 = inStream; final OutputStream out2 = outStream; User ticket = remoteId.getTicket(); if (authMethod == AuthMethod.KERBEROS) { UserGroupInformation ugi = ticket.getUGI(); if (ugi != null && ugi.getRealUser() != null) { ticket = userProvider.create(ugi.getRealUser()); } } boolean continueSasl = false; try { continueSasl = ticket.runAs(new PrivilegedExceptionAction<Boolean>() { @Override public Boolean run() throws IOException { return setupSaslConnection(in2, out2); } }); } catch (Exception ex) { if (rand == null) { rand = new Random(); } handleSaslConnectionFailure(numRetries++, MAX_RETRIES, ex, rand, ticket); continue; } if (continueSasl) { // Sasl connect is successful. Let's set up Sasl i/o streams. inStream = saslRpcClient.getInputStream(inStream); outStream = saslRpcClient.getOutputStream(outStream); } else { // fall back to simple auth because server told us so. authMethod = AuthMethod.SIMPLE; header = new SecureConnectionHeader(header.getProtocol(), header.getUser(), authMethod); useSasl = false; } } this.in = new DataInputStream(new BufferedInputStream (new PingInputStream(inStream))); this.out = new DataOutputStream (new BufferedOutputStream(outStream)); writeHeader(); // update last activity time touch(); // start the receiver thread after the socket connection has been set up start(); return; } } catch (IOException e) { markClosed(e); close(); throw e; } }
private void processHeader(byte[] buf) throws IOException { DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf)); header.readFields(in); try { String protocolClassName = header.getProtocol(); if (protocolClassName != null) { protocol = getProtocolClass(header.getProtocol(), conf); } } catch (ClassNotFoundException cnfe) { throw new IOException("Unknown protocol: " + header.getProtocol()); } User protocolUser = header.getUser(); if (!useSasl) { ticket = protocolUser; if (ticket != null) { ticket.getUGI().setAuthenticationMethod(AuthMethod.SIMPLE.authenticationMethod); } } else { // user is authenticated ticket.getUGI().setAuthenticationMethod(authMethod.authenticationMethod); //Now we check if this is a proxy user case. If the protocol user is //different from the 'user', it is a proxy user scenario. However, //this is not allowed if user authenticated with DIGEST. if ((protocolUser != null) && (!protocolUser.getName().equals(ticket.getName()))) { if (authMethod == AuthMethod.DIGEST) { // Not allowed to doAs if token authentication is used throw new AccessControlException("Authenticated user (" + ticket + ") doesn't match what the client claims to be (" + protocolUser + ")"); } else { // Effective user can be different from authenticated user // for simple auth or kerberos auth // The user is the real user. Now we create a proxy user UserGroupInformation realUser = ticket.getUGI(); ticket = userProvider.create( UserGroupInformation.createProxyUser(protocolUser.getName(), realUser)); // Now the user is a proxy user, set Authentication method Proxy. ticket.getUGI().setAuthenticationMethod(AuthenticationMethod.PROXY); } } } }
public SecureConnection(ConnectionId remoteId) throws IOException { super(remoteId); this.server = remoteId.getAddress(); User ticket = remoteId.getTicket(); Class<?> protocol = remoteId.getProtocol(); this.useSasl = User.isHBaseSecurityEnabled(conf); if (useSasl && protocol != null) { TokenInfo tokenInfo = protocol.getAnnotation(TokenInfo.class); if (tokenInfo != null) { TokenSelector<? extends TokenIdentifier> tokenSelector = tokenHandlers.get(tokenInfo.value()); if (tokenSelector != null) { token = tokenSelector.selectToken(new Text(clusterId), ticket.getUGI().getTokens()); } else if (LOG.isDebugEnabled()) { LOG.debug("No token selector found for type "+tokenInfo.value()); } } KerberosInfo krbInfo = protocol.getAnnotation(KerberosInfo.class); if (krbInfo != null) { String serverKey = krbInfo.serverPrincipal(); if (serverKey == null) { throw new IOException( "Can't obtain server Kerberos config key from KerberosInfo"); } serverPrincipal = SecurityUtil.getServerPrincipal( conf.get(serverKey), server.getAddress().getCanonicalHostName().toLowerCase()); if (LOG.isDebugEnabled()) { LOG.debug("RPC Server Kerberos principal name for protocol=" + protocol.getCanonicalName() + " is " + serverPrincipal); } } } if (!useSasl) { authMethod = AuthMethod.SIMPLE; } else if (token != null) { authMethod = AuthMethod.DIGEST; } else { authMethod = AuthMethod.KERBEROS; } header = new SecureConnectionHeader( protocol == null ? null : protocol.getName(), ticket, authMethod); if (LOG.isDebugEnabled()) LOG.debug("Use " + authMethod + " authentication for protocol " + protocol.getSimpleName()); reloginMaxBackoff = conf.getInt("hbase.security.relogin.maxbackoff", 5000); }
@Override protected synchronized void setupIOstreams() throws IOException, InterruptedException { if (socket != null || shouldCloseConnection.get()) { return; } try { if (LOG.isDebugEnabled()) { LOG.debug("Connecting to "+server); } short numRetries = 0; final short MAX_RETRIES = 5; Random rand = null; while (true) { setupConnection(); InputStream inStream = NetUtils.getInputStream(socket); OutputStream outStream = NetUtils.getOutputStream(socket); writeRpcHeader(outStream); if (useSasl) { final InputStream in2 = inStream; final OutputStream out2 = outStream; User ticket = remoteId.getTicket(); if (authMethod == AuthMethod.KERBEROS) { UserGroupInformation ugi = ticket.getUGI(); if (ugi != null && ugi.getRealUser() != null) { ticket = User.create(ugi.getRealUser()); } } boolean continueSasl = false; try { continueSasl = ticket.runAs(new PrivilegedExceptionAction<Boolean>() { @Override public Boolean run() throws IOException { return setupSaslConnection(in2, out2); } }); } catch (Exception ex) { if (rand == null) { rand = new Random(); } handleSaslConnectionFailure(numRetries++, MAX_RETRIES, ex, rand, ticket); continue; } if (continueSasl) { // Sasl connect is successful. Let's set up Sasl i/o streams. inStream = saslRpcClient.getInputStream(inStream); outStream = saslRpcClient.getOutputStream(outStream); } else { // fall back to simple auth because server told us so. authMethod = AuthMethod.SIMPLE; header = new SecureConnectionHeader(header.getProtocol(), header.getUser(), authMethod); useSasl = false; } } this.in = new DataInputStream(new BufferedInputStream (new PingInputStream(inStream))); this.out = new DataOutputStream (new BufferedOutputStream(outStream)); writeHeader(); // update last activity time touch(); // start the receiver thread after the socket connection has been set up start(); return; } } catch (IOException e) { markClosed(e); close(); throw e; } }
private void processHeader(byte[] buf) throws IOException { DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf)); header.readFields(in); try { String protocolClassName = header.getProtocol(); if (protocolClassName != null) { protocol = getProtocolClass(header.getProtocol(), conf); } } catch (ClassNotFoundException cnfe) { throw new IOException("Unknown protocol: " + header.getProtocol()); } User protocolUser = header.getUser(); if (!useSasl) { ticket = protocolUser; if (ticket != null) { ticket.getUGI().setAuthenticationMethod(AuthMethod.SIMPLE.authenticationMethod); } } else { // user is authenticated ticket.getUGI().setAuthenticationMethod(authMethod.authenticationMethod); //Now we check if this is a proxy user case. If the protocol user is //different from the 'user', it is a proxy user scenario. However, //this is not allowed if user authenticated with DIGEST. if ((protocolUser != null) && (!protocolUser.getName().equals(ticket.getName()))) { if (authMethod == AuthMethod.DIGEST) { // Not allowed to doAs if token authentication is used throw new AccessControlException("Authenticated user (" + ticket + ") doesn't match what the client claims to be (" + protocolUser + ")"); } else { // Effective user can be different from authenticated user // for simple auth or kerberos auth // The user is the real user. Now we create a proxy user UserGroupInformation realUser = ticket.getUGI(); ticket = User.create( UserGroupInformation.createProxyUser(protocolUser.getName(), realUser)); // Now the user is a proxy user, set Authentication method Proxy. ticket.getUGI().setAuthenticationMethod(AuthenticationMethod.PROXY); } } } }