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; 023import javax.security.auth.callback.Callback; 024import javax.security.auth.callback.CallbackHandler; 025import javax.security.auth.callback.UnsupportedCallbackException; 026import javax.security.sasl.AuthorizeCallback; 027import javax.security.sasl.Sasl; 028import javax.security.sasl.SaslException; 029import org.apache.hadoop.hbase.security.AccessDeniedException; 030import org.apache.hadoop.hbase.security.SaslUtil; 031import org.apache.hadoop.security.UserGroupInformation; 032import org.apache.hadoop.security.token.SecretManager; 033import org.apache.hadoop.security.token.TokenIdentifier; 034import org.apache.yetus.audience.InterfaceAudience; 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038@InterfaceAudience.Private 039public class GssSaslServerAuthenticationProvider extends GssSaslAuthenticationProvider 040 implements SaslServerAuthenticationProvider { 041 private static final Logger LOG = 042 LoggerFactory.getLogger(GssSaslServerAuthenticationProvider.class); 043 044 @Override 045 public AttemptingUserProvidingSaslServer 046 createServer(SecretManager<TokenIdentifier> secretManager, Map<String, String> saslProps) 047 throws IOException { 048 UserGroupInformation current = UserGroupInformation.getCurrentUser(); 049 String fullName = current.getUserName(); 050 LOG.debug("Server's Kerberos principal name is {}", fullName); 051 String[] names = SaslUtil.splitKerberosName(fullName); 052 if (names.length != 3) { 053 throw new AccessDeniedException( 054 "Kerberos principal does NOT contain an instance (hostname): " + fullName); 055 } 056 try { 057 return current.doAs(new PrivilegedExceptionAction<AttemptingUserProvidingSaslServer>() { 058 @Override 059 public AttemptingUserProvidingSaslServer run() throws SaslException { 060 return new AttemptingUserProvidingSaslServer( 061 Sasl.createSaslServer(getSaslAuthMethod().getSaslMechanism(), names[0], names[1], 062 saslProps, new SaslGssCallbackHandler()), 063 () -> null); 064 } 065 }); 066 } catch (InterruptedException e) { 067 Thread.currentThread().interrupt(); 068 throw new RuntimeException("Failed to construct GSS SASL server"); 069 } 070 } 071 072 /** CallbackHandler for SASL GSSAPI Kerberos mechanism */ 073 private static class SaslGssCallbackHandler implements CallbackHandler { 074 075 /** {@inheritDoc} */ 076 @Override 077 public void handle(Callback[] callbacks) throws UnsupportedCallbackException { 078 AuthorizeCallback ac = null; 079 for (Callback callback : callbacks) { 080 if (callback instanceof AuthorizeCallback) { 081 ac = (AuthorizeCallback) callback; 082 } else { 083 throw new UnsupportedCallbackException(callback, "Unrecognized SASL GSSAPI Callback"); 084 } 085 } 086 if (ac != null) { 087 String authid = ac.getAuthenticationID(); 088 String authzid = ac.getAuthorizationID(); 089 if (authid.equals(authzid)) { 090 ac.setAuthorized(true); 091 } else { 092 ac.setAuthorized(false); 093 } 094 if (ac.isAuthorized()) { 095 LOG.debug("SASL server GSSAPI callback: setting canonicalized client ID: {}", authzid); 096 ac.setAuthorizedID(authzid); 097 } 098 } 099 } 100 } 101 102 @Override 103 public boolean supportsProtocolAuthentication() { 104 return true; 105 } 106 107 @Override 108 public UserGroupInformation getAuthorizedUgi(String authzId, 109 SecretManager<TokenIdentifier> secretManager) throws IOException { 110 UserGroupInformation ugi = UserGroupInformation.createRemoteUser(authzId); 111 ugi.setAuthenticationMethod(getSaslAuthMethod().getAuthMethod()); 112 return ugi; 113 } 114}