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
019package org.apache.hadoop.yarn.security.client;
020
021
022import java.io.IOException;
023import java.net.InetSocketAddress;
024
025import org.apache.hadoop.classification.InterfaceAudience.Private;
026import org.apache.hadoop.classification.InterfaceAudience.Public;
027import org.apache.hadoop.classification.InterfaceStability.Evolving;
028import org.apache.hadoop.conf.Configuration;
029import org.apache.hadoop.io.Text;
030import org.apache.hadoop.ipc.RPC;
031import org.apache.hadoop.net.NetUtils;
032import org.apache.hadoop.security.SecurityUtil;
033import org.apache.hadoop.security.token.Token;
034import org.apache.hadoop.security.token.TokenRenewer;
035import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenIdentifier;
036import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager;
037import org.apache.hadoop.yarn.api.ApplicationClientProtocol;
038import org.apache.hadoop.yarn.api.protocolrecords.CancelDelegationTokenRequest;
039import org.apache.hadoop.yarn.api.protocolrecords.RenewDelegationTokenRequest;
040import org.apache.hadoop.yarn.client.ClientRMProxy;
041import org.apache.hadoop.yarn.conf.YarnConfiguration;
042import org.apache.hadoop.yarn.exceptions.YarnException;
043import org.apache.hadoop.yarn.util.Records;
044
045/**
046 * Delegation Token Identifier that identifies the delegation tokens from the 
047 * Resource Manager. 
048 */
049@Public
050@Evolving
051public class RMDelegationTokenIdentifier extends AbstractDelegationTokenIdentifier {
052
053  public static final Text KIND_NAME = new Text("RM_DELEGATION_TOKEN");
054  
055  public RMDelegationTokenIdentifier() {
056  }
057  
058  /**
059   * Create a new delegation token identifier
060   * @param owner the effective username of the token owner
061   * @param renewer the username of the renewer
062   * @param realUser the real username of the token owner
063   */
064  public RMDelegationTokenIdentifier(Text owner, Text renewer, Text realUser) {
065    super(owner, renewer, realUser);
066  }
067
068  @Override
069  public Text getKind() {
070    return KIND_NAME;
071  }
072  
073  public static class Renewer extends TokenRenewer {
074
075    @Override
076    public boolean handleKind(Text kind) {
077      return KIND_NAME.equals(kind);
078    }
079
080    @Override
081    public boolean isManaged(Token<?> token) throws IOException {
082      return true;
083    }
084
085    private static
086    AbstractDelegationTokenSecretManager<RMDelegationTokenIdentifier> localSecretManager;
087    private static InetSocketAddress localServiceAddress;
088    
089    @Private
090    public static void setSecretManager(
091        AbstractDelegationTokenSecretManager<RMDelegationTokenIdentifier> secretManager,
092        InetSocketAddress serviceAddress) {
093      localSecretManager = secretManager;
094      localServiceAddress = serviceAddress;
095    }
096    
097    @SuppressWarnings("unchecked")
098    @Override
099    public long renew(Token<?> token, Configuration conf) throws IOException,
100        InterruptedException {
101      final ApplicationClientProtocol rmClient = getRmClient(token, conf);
102      if (rmClient != null) {
103        try {
104          RenewDelegationTokenRequest request =
105              Records.newRecord(RenewDelegationTokenRequest.class);
106          request.setDelegationToken(convertToProtoToken(token));
107          return rmClient.renewDelegationToken(request).getNextExpirationTime();
108        } catch (YarnException e) {
109          throw new IOException(e);
110        } finally {
111          RPC.stopProxy(rmClient);
112        }
113      } else {
114        return localSecretManager.renewToken(
115            (Token<RMDelegationTokenIdentifier>)token, getRenewer(token));
116      }
117    }
118
119    @SuppressWarnings("unchecked")
120    @Override
121    public void cancel(Token<?> token, Configuration conf) throws IOException,
122        InterruptedException {
123      final ApplicationClientProtocol rmClient = getRmClient(token, conf);
124      if (rmClient != null) {
125        try {
126          CancelDelegationTokenRequest request =
127              Records.newRecord(CancelDelegationTokenRequest.class);
128          request.setDelegationToken(convertToProtoToken(token));
129          rmClient.cancelDelegationToken(request);
130        } catch (YarnException e) {
131          throw new IOException(e);
132        } finally {
133          RPC.stopProxy(rmClient);
134        }
135      } else {
136        localSecretManager.cancelToken(
137            (Token<RMDelegationTokenIdentifier>)token, getRenewer(token));
138      }
139    }
140    
141    private static ApplicationClientProtocol getRmClient(Token<?> token,
142        Configuration conf) throws IOException {
143      String[] services = token.getService().toString().split(",");
144      for (String service : services) {
145        InetSocketAddress addr = NetUtils.createSocketAddr(service);
146        if (localSecretManager != null) {
147          // return null if it's our token
148          if (localServiceAddress.getAddress().isAnyLocalAddress()) {
149            if (NetUtils.isLocalAddress(addr.getAddress()) &&
150                addr.getPort() == localServiceAddress.getPort()) {
151              return null;
152            }
153          } else if (addr.equals(localServiceAddress)) {
154            return null;
155          }
156        }
157      }
158      return ClientRMProxy.createRMProxy(conf, ApplicationClientProtocol.class);
159    }
160
161    // get renewer so we can always renew our own tokens
162    @SuppressWarnings("unchecked")
163    private static String getRenewer(Token<?> token) throws IOException {
164      return ((Token<RMDelegationTokenIdentifier>)token).decodeIdentifier()
165          .getRenewer().toString();
166    }
167    
168    private static org.apache.hadoop.yarn.api.records.Token
169        convertToProtoToken(Token<?> token) {
170      return org.apache.hadoop.yarn.api.records.Token.newInstance(
171        token.getIdentifier(), token.getKind().toString(), token.getPassword(),
172        token.getService().toString());
173    }
174  }
175}