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 */ 018 package org.apache.hadoop.lib.service.security; 019 020 import org.apache.hadoop.classification.InterfaceAudience; 021 import org.apache.hadoop.fs.http.server.HttpFSServerWebApp; 022 import org.apache.hadoop.hdfs.web.SWebHdfsFileSystem; 023 import org.apache.hadoop.hdfs.web.WebHdfsFileSystem; 024 import org.apache.hadoop.io.Text; 025 import org.apache.hadoop.lib.server.BaseService; 026 import org.apache.hadoop.lib.server.ServerException; 027 import org.apache.hadoop.lib.server.ServiceException; 028 import org.apache.hadoop.lib.service.DelegationTokenIdentifier; 029 import org.apache.hadoop.lib.service.DelegationTokenManager; 030 import org.apache.hadoop.lib.service.DelegationTokenManagerException; 031 import org.apache.hadoop.security.SecurityUtil; 032 import org.apache.hadoop.security.UserGroupInformation; 033 import org.apache.hadoop.security.token.Token; 034 import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager; 035 036 import java.io.ByteArrayInputStream; 037 import java.io.DataInputStream; 038 import java.io.IOException; 039 040 /** 041 * DelegationTokenManager service implementation. 042 */ 043 @InterfaceAudience.Private 044 public class DelegationTokenManagerService extends BaseService 045 implements DelegationTokenManager { 046 047 private static final String PREFIX = "delegation.token.manager"; 048 049 private static final String UPDATE_INTERVAL = "update.interval"; 050 051 private static final String MAX_LIFETIME = "max.lifetime"; 052 053 private static final String RENEW_INTERVAL = "renew.interval"; 054 055 private static final long HOUR = 60 * 60 * 1000; 056 private static final long DAY = 24 * HOUR; 057 058 DelegationTokenSecretManager secretManager = null; 059 060 private Text tokenKind; 061 062 public DelegationTokenManagerService() { 063 super(PREFIX); 064 } 065 066 /** 067 * Initializes the service. 068 * 069 * @throws ServiceException thrown if the service could not be initialized. 070 */ 071 @Override 072 protected void init() throws ServiceException { 073 074 long updateInterval = getServiceConfig().getLong(UPDATE_INTERVAL, DAY); 075 long maxLifetime = getServiceConfig().getLong(MAX_LIFETIME, 7 * DAY); 076 long renewInterval = getServiceConfig().getLong(RENEW_INTERVAL, DAY); 077 tokenKind = (HttpFSServerWebApp.get().isSslEnabled()) 078 ? SWebHdfsFileSystem.TOKEN_KIND : WebHdfsFileSystem.TOKEN_KIND; 079 secretManager = new DelegationTokenSecretManager(tokenKind, updateInterval, 080 maxLifetime, 081 renewInterval, HOUR); 082 try { 083 secretManager.startThreads(); 084 } catch (IOException ex) { 085 throw new ServiceException(ServiceException.ERROR.S12, 086 DelegationTokenManager.class.getSimpleName(), 087 ex.toString(), ex); 088 } 089 } 090 091 /** 092 * Destroys the service. 093 */ 094 @Override 095 public void destroy() { 096 secretManager.stopThreads(); 097 super.destroy(); 098 } 099 100 /** 101 * Returns the service interface. 102 * 103 * @return the service interface. 104 */ 105 @Override 106 public Class getInterface() { 107 return DelegationTokenManager.class; 108 } 109 110 /** 111 * Creates a delegation token. 112 * 113 * @param ugi UGI creating the token. 114 * @param renewer token renewer. 115 * @return new delegation token. 116 * @throws DelegationTokenManagerException thrown if the token could not be 117 * created. 118 */ 119 @Override 120 public Token<DelegationTokenIdentifier> createToken(UserGroupInformation ugi, 121 String renewer) 122 throws DelegationTokenManagerException { 123 renewer = (renewer == null) ? ugi.getShortUserName() : renewer; 124 String user = ugi.getUserName(); 125 Text owner = new Text(user); 126 Text realUser = null; 127 if (ugi.getRealUser() != null) { 128 realUser = new Text(ugi.getRealUser().getUserName()); 129 } 130 DelegationTokenIdentifier tokenIdentifier = 131 new DelegationTokenIdentifier(tokenKind, owner, new Text(renewer), realUser); 132 Token<DelegationTokenIdentifier> token = 133 new Token<DelegationTokenIdentifier>(tokenIdentifier, secretManager); 134 try { 135 SecurityUtil.setTokenService(token, 136 HttpFSServerWebApp.get().getAuthority()); 137 } catch (ServerException ex) { 138 throw new DelegationTokenManagerException( 139 DelegationTokenManagerException.ERROR.DT04, ex.toString(), ex); 140 } 141 return token; 142 } 143 144 /** 145 * Renews a delegation token. 146 * 147 * @param token delegation token to renew. 148 * @param renewer token renewer. 149 * @return epoc expiration time. 150 * @throws DelegationTokenManagerException thrown if the token could not be 151 * renewed. 152 */ 153 @Override 154 public long renewToken(Token<DelegationTokenIdentifier> token, String renewer) 155 throws DelegationTokenManagerException { 156 try { 157 return secretManager.renewToken(token, renewer); 158 } catch (IOException ex) { 159 throw new DelegationTokenManagerException( 160 DelegationTokenManagerException.ERROR.DT02, ex.toString(), ex); 161 } 162 } 163 164 /** 165 * Cancels a delegation token. 166 * 167 * @param token delegation token to cancel. 168 * @param canceler token canceler. 169 * @throws DelegationTokenManagerException thrown if the token could not be 170 * canceled. 171 */ 172 @Override 173 public void cancelToken(Token<DelegationTokenIdentifier> token, 174 String canceler) 175 throws DelegationTokenManagerException { 176 try { 177 secretManager.cancelToken(token, canceler); 178 } catch (IOException ex) { 179 throw new DelegationTokenManagerException( 180 DelegationTokenManagerException.ERROR.DT03, ex.toString(), ex); 181 } 182 } 183 184 /** 185 * Verifies a delegation token. 186 * 187 * @param token delegation token to verify. 188 * @return the UGI for the token. 189 * @throws DelegationTokenManagerException thrown if the token could not be 190 * verified. 191 */ 192 @Override 193 public UserGroupInformation verifyToken(Token<DelegationTokenIdentifier> token) 194 throws DelegationTokenManagerException { 195 ByteArrayInputStream buf = new ByteArrayInputStream(token.getIdentifier()); 196 DataInputStream dis = new DataInputStream(buf); 197 DelegationTokenIdentifier id = new DelegationTokenIdentifier(tokenKind); 198 try { 199 id.readFields(dis); 200 dis.close(); 201 secretManager.verifyToken(id, token.getPassword()); 202 } catch (Exception ex) { 203 throw new DelegationTokenManagerException( 204 DelegationTokenManagerException.ERROR.DT01, ex.toString(), ex); 205 } 206 return id.getUser(); 207 } 208 209 private static class DelegationTokenSecretManager 210 extends AbstractDelegationTokenSecretManager<DelegationTokenIdentifier> { 211 212 private Text tokenKind; 213 214 /** 215 * Create a secret manager 216 * 217 * @param delegationKeyUpdateInterval the number of seconds for rolling new 218 * secret keys. 219 * @param delegationTokenMaxLifetime the maximum lifetime of the delegation 220 * tokens 221 * @param delegationTokenRenewInterval how often the tokens must be renewed 222 * @param delegationTokenRemoverScanInterval how often the tokens are 223 * scanned 224 * for expired tokens 225 */ 226 public DelegationTokenSecretManager(Text tokenKind, long delegationKeyUpdateInterval, 227 long delegationTokenMaxLifetime, 228 long delegationTokenRenewInterval, 229 long delegationTokenRemoverScanInterval) { 230 super(delegationKeyUpdateInterval, delegationTokenMaxLifetime, 231 delegationTokenRenewInterval, delegationTokenRemoverScanInterval); 232 this.tokenKind = tokenKind; 233 } 234 235 @Override 236 public DelegationTokenIdentifier createIdentifier() { 237 return new DelegationTokenIdentifier(tokenKind); 238 } 239 240 } 241 242 }