001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.security.provider; 019 020import java.io.IOException; 021import java.security.PrivilegedExceptionAction; 022import java.util.Map; 023 024import javax.security.auth.callback.Callback; 025import javax.security.auth.callback.CallbackHandler; 026import javax.security.auth.callback.UnsupportedCallbackException; 027import javax.security.sasl.AuthorizeCallback; 028import javax.security.sasl.Sasl; 029import javax.security.sasl.SaslException; 030 031import org.apache.hadoop.hbase.security.AccessDeniedException; 032import org.apache.hadoop.hbase.security.SaslUtil; 033import org.apache.hadoop.security.UserGroupInformation; 034import org.apache.hadoop.security.token.SecretManager; 035import org.apache.hadoop.security.token.TokenIdentifier; 036import org.apache.yetus.audience.InterfaceAudience; 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040@InterfaceAudience.Private 041public class GssSaslServerAuthenticationProvider extends GssSaslAuthenticationProvider 042 implements SaslServerAuthenticationProvider { 043 private static final Logger LOG = LoggerFactory.getLogger( 044 GssSaslServerAuthenticationProvider.class); 045 046 @Override 047 public AttemptingUserProvidingSaslServer createServer( 048 SecretManager<TokenIdentifier> secretManager, 049 Map<String, String> saslProps) throws IOException { 050 UserGroupInformation current = UserGroupInformation.getCurrentUser(); 051 String fullName = current.getUserName(); 052 LOG.debug("Server's Kerberos principal name is {}", fullName); 053 String[] names = SaslUtil.splitKerberosName(fullName); 054 if (names.length != 3) { 055 throw new AccessDeniedException( 056 "Kerberos principal does NOT contain an instance (hostname): " + fullName); 057 } 058 try { 059 return current.doAs(new PrivilegedExceptionAction<AttemptingUserProvidingSaslServer>() { 060 @Override 061 public AttemptingUserProvidingSaslServer run() throws SaslException { 062 return new AttemptingUserProvidingSaslServer(Sasl.createSaslServer( 063 getSaslAuthMethod().getSaslMechanism(), names[0], names[1], saslProps, 064 new SaslGssCallbackHandler()), () -> null); 065 } 066 }); 067 } catch (InterruptedException e) { 068 Thread.currentThread().interrupt(); 069 throw new RuntimeException("Failed to construct GSS SASL server"); 070 } 071 } 072 073 /** CallbackHandler for SASL GSSAPI Kerberos mechanism */ 074 private static class SaslGssCallbackHandler implements CallbackHandler { 075 076 /** {@inheritDoc} */ 077 @Override 078 public void handle(Callback[] callbacks) throws UnsupportedCallbackException { 079 AuthorizeCallback ac = null; 080 for (Callback callback : callbacks) { 081 if (callback instanceof AuthorizeCallback) { 082 ac = (AuthorizeCallback) callback; 083 } else { 084 throw new UnsupportedCallbackException(callback, "Unrecognized SASL GSSAPI Callback"); 085 } 086 } 087 if (ac != null) { 088 String authid = ac.getAuthenticationID(); 089 String authzid = ac.getAuthorizationID(); 090 if (authid.equals(authzid)) { 091 ac.setAuthorized(true); 092 } else { 093 ac.setAuthorized(false); 094 } 095 if (ac.isAuthorized()) { 096 LOG.debug("SASL server GSSAPI callback: setting canonicalized client ID: {}", authzid); 097 ac.setAuthorizedID(authzid); 098 } 099 } 100 } 101 } 102 103 @Override 104 public boolean supportsProtocolAuthentication() { 105 return true; 106 } 107 108 @Override 109 public UserGroupInformation getAuthorizedUgi(String authzId, 110 SecretManager<TokenIdentifier> secretManager) throws IOException { 111 UserGroupInformation ugi = UserGroupInformation.createRemoteUser(authzId); 112 ugi.setAuthenticationMethod(getSaslAuthMethod().getAuthMethod()); 113 return ugi; 114 } 115}