View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.security.token;
20  
21  import java.io.IOException;
22  
23  import com.google.protobuf.RpcCallback;
24  import com.google.protobuf.RpcController;
25  import com.google.protobuf.Service;
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.hbase.classification.InterfaceAudience;
29  import org.apache.hadoop.hbase.Coprocessor;
30  import org.apache.hadoop.hbase.CoprocessorEnvironment;
31  import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
32  import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
33  import org.apache.hadoop.hbase.ipc.RpcServer;
34  import org.apache.hadoop.hbase.ipc.RpcServerInterface;
35  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
36  import org.apache.hadoop.hbase.protobuf.ResponseConverter;
37  import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos;
38  import org.apache.hadoop.hbase.security.AccessDeniedException;
39  import org.apache.hadoop.hbase.security.User;
40  import org.apache.hadoop.security.UserGroupInformation;
41  import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
42  import org.apache.hadoop.security.token.SecretManager;
43  import org.apache.hadoop.security.token.Token;
44  
45  /**
46   * Provides a service for obtaining authentication tokens via the
47   * {@link AuthenticationProtos} AuthenticationService coprocessor service.
48   */
49  @InterfaceAudience.Private
50  public class TokenProvider implements AuthenticationProtos.AuthenticationService.Interface,
51      Coprocessor, CoprocessorService {
52  
53    private static final Log LOG = LogFactory.getLog(TokenProvider.class);
54  
55    private AuthenticationTokenSecretManager secretManager;
56  
57  
58    @Override
59    public void start(CoprocessorEnvironment env) {
60      // if running at region
61      if (env instanceof RegionCoprocessorEnvironment) {
62        RegionCoprocessorEnvironment regionEnv =
63            (RegionCoprocessorEnvironment)env;
64        RpcServerInterface server = regionEnv.getRegionServerServices().getRpcServer();
65        SecretManager<?> mgr = ((RpcServer)server).getSecretManager();
66        if (mgr instanceof AuthenticationTokenSecretManager) {
67          secretManager = (AuthenticationTokenSecretManager)mgr;
68        }
69      }
70    }
71  
72    @Override
73    public void stop(CoprocessorEnvironment env) throws IOException {
74    }
75  
76    /**
77     * @param ugi A user group information.
78     * @return true if delegation token operation is allowed
79     */
80    private boolean isAllowedDelegationTokenOp(UserGroupInformation ugi) throws IOException {
81      AuthenticationMethod authMethod = ugi.getAuthenticationMethod();
82      if (authMethod == AuthenticationMethod.PROXY) {
83        authMethod = ugi.getRealUser().getAuthenticationMethod();
84      }
85      if (authMethod != AuthenticationMethod.KERBEROS
86          && authMethod != AuthenticationMethod.KERBEROS_SSL
87          && authMethod != AuthenticationMethod.CERTIFICATE) {
88        return false;
89      }
90      return true;
91    }
92  
93    // AuthenticationService implementation
94  
95    @Override
96    public Service getService() {
97      return AuthenticationProtos.AuthenticationService.newReflectiveService(this);
98    }
99  
100   @Override
101   public void getAuthenticationToken(RpcController controller,
102                                      AuthenticationProtos.GetAuthenticationTokenRequest request,
103                                      RpcCallback<AuthenticationProtos.GetAuthenticationTokenResponse> done) {
104     AuthenticationProtos.GetAuthenticationTokenResponse.Builder response =
105         AuthenticationProtos.GetAuthenticationTokenResponse.newBuilder();
106 
107     try {
108       if (secretManager == null) {
109         throw new IOException(
110             "No secret manager configured for token authentication");
111       }
112 
113       User currentUser = RpcServer.getRequestUser();
114       UserGroupInformation ugi = null;
115       if (currentUser != null) {
116         ugi = currentUser.getUGI();
117       }
118       if (currentUser == null) {
119         throw new AccessDeniedException("No authenticated user for request!");
120       } else if (!isAllowedDelegationTokenOp(ugi)) {
121         LOG.warn("Token generation denied for user="+currentUser.getName()
122             +", authMethod="+ugi.getAuthenticationMethod());
123         throw new AccessDeniedException(
124             "Token generation only allowed for Kerberos authenticated clients");
125       }
126 
127       Token<AuthenticationTokenIdentifier> token =
128           secretManager.generateToken(currentUser.getName());
129       response.setToken(ProtobufUtil.toToken(token)).build();
130     } catch (IOException ioe) {
131       ResponseConverter.setControllerException(controller, ioe);
132     }
133     done.run(response.build());
134   }
135 
136   @Override
137   public void whoAmI(RpcController controller, AuthenticationProtos.WhoAmIRequest request,
138                      RpcCallback<AuthenticationProtos.WhoAmIResponse> done) {
139     User requestUser = RpcServer.getRequestUser();
140     AuthenticationProtos.WhoAmIResponse.Builder response =
141         AuthenticationProtos.WhoAmIResponse.newBuilder();
142     if (requestUser != null) {
143       response.setUsername(requestUser.getShortName());
144       AuthenticationMethod method = requestUser.getUGI().getAuthenticationMethod();
145       if (method != null) {
146         response.setAuthMethod(method.name());
147       }
148     }
149     done.run(response.build());
150   }
151 }