001package org.apache.hadoop.security.rpcauth;
002
003import java.io.DataInput;
004import java.io.IOException;
005import java.util.ArrayList;
006import java.util.LinkedHashMap;
007import java.util.List;
008import java.util.Map;
009
010import org.apache.commons.logging.Log;
011import org.apache.commons.logging.LogFactory;
012import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
013
014public class RpcAuthRegistry {
015  private static final Log LOG =
016      LogFactory.getLog(RpcAuthRegistry.class);
017  private static final Map<Byte, RpcAuthMethod> authMethods =
018      new LinkedHashMap<Byte, RpcAuthMethod>();
019  private static final Map<String, RpcAuthMethod> loginModuleMap =
020      new LinkedHashMap<String, RpcAuthMethod>();
021
022  /**
023   * Pre-defined authentication methods
024   */
025  public static final RpcAuthMethod KERBEROS = KerberosAuthMethod.INSTANCE;
026  public static final RpcAuthMethod FAKE_KERBEROS = FakeKerberosAuthMethod.INSTANCE;
027  public static final RpcAuthMethod SIMPLE = SimpleAuthMethod.INSTANCE;
028  public static final RpcAuthMethod DIGEST = DigestAuthMethod.INSTANCE;
029
030  static {
031    addRpcAuthMethod(SIMPLE);
032    addRpcAuthMethod(KERBEROS);
033    addRpcAuthMethod(DIGEST);
034    addRpcAuthMethod(FAKE_KERBEROS);
035  }
036
037  public synchronized static void addRpcAuthMethod(RpcAuthMethod authMethod) {
038    if (authMethods.containsKey(authMethod.authcode)) {
039      RpcAuthMethod oldMethod = authMethods.get(authMethod.authcode);
040      if (!oldMethod.getClass().equals(authMethod.getClass())) {
041        throw new IllegalArgumentException(
042          String.format("Duplicate authcode [%d] for '%s'. Already registerd for '%s'.",
043            authMethod.authcode,
044            authMethod.getClass().getCanonicalName(),
045            oldMethod.getClass().getCanonicalName()
046        ));
047      }
048    }
049
050    for (String module : authMethod.loginModules()) {
051      if (loginModuleMap.containsKey(module)) {
052        RpcAuthMethod oldMethod = loginModuleMap.get(module);
053        if (!oldMethod.getClass().equals(authMethod.getClass())) {
054          throw new IllegalArgumentException(
055              String.format("Duplicate login module [%s] for '%s'. Already registerd for '%s'.",
056                  module,
057                  authMethod.getClass().getCanonicalName(),
058                  oldMethod.getClass().getCanonicalName()
059                  ));
060        }
061      }
062      loginModuleMap.put(module, authMethod);
063    }
064    authMethods.put(authMethod.authcode, authMethod);
065    if (LOG.isDebugEnabled()) {
066      LOG.debug("Added " + authMethod + " to registry.");
067    }
068  }
069
070  /** Return the RpcAuthMethod for given JAAS login module */
071  public static RpcAuthMethod getAuthMethodForLoginModule(String loginModule) {
072    return loginModuleMap.get(loginModule);
073  }
074
075  /** Return the RpcAuthMethod for given auth code */
076  public static RpcAuthMethod getAuthMethod(byte authCode) {
077    return authMethods.get(authCode);
078  }
079
080  public static RpcAuthMethod getAuthMethod(String name) {
081    for (RpcAuthMethod method : authMethods.values()) {
082      if (method.simpleName.equalsIgnoreCase(name)) {
083        return method;
084      }
085    }
086    LOG.warn("No RpcAuthMethod registerd for name " + name);
087    return null;
088  }
089
090  public static RpcAuthMethod getAuthMethod(AuthenticationMethod authenticationMethod) {
091    for (RpcAuthMethod method : authMethods.values()) {
092      if (method.authenticationMethod.equals(authenticationMethod)) {
093        return method;
094      }
095    }
096    LOG.warn("No RpcAuthMethod registerd for authentication method " + authenticationMethod);
097    return null;
098  }
099
100  /** Read from in. */
101  @Deprecated
102  public static RpcAuthMethod readAuthMethod(DataInput in) throws IOException {
103    byte code = in.readByte();
104    if (!authMethods.containsKey(code)) {
105      LOG.warn("No RpcAuthMethod registerd for auth code " + code);
106    }
107    return authMethods.get(code);
108  }
109
110  /**
111   * Return the ordered list of auth method for given comma separated names.
112   * To be used for logging purpose only.
113   */
114  @Deprecated
115  public static List<RpcAuthMethod> getAuthMethodList(byte[] authCodes) {
116    List<RpcAuthMethod> list = new ArrayList<RpcAuthMethod>();
117    for (byte code : authCodes) {
118      RpcAuthMethod method = authMethods.get(code);
119      if (method == null) {
120        String name = "UNKNOWN(" + code + ")";
121        method = new RpcAuthMethod(code, name, name, null) {};
122      }
123      list.add(method);
124    }
125    return list;
126  }
127
128}