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