::Go back to Oozie Documentation Index::

Creating Custom Authentication

Hadoop-Auth Authentication Interfaces and classes

1. org.apache.hadoop.security.authentication.client.Authenticator: Interface for client authentication mechanisms.

The following authenticators are provided in hadoop-auth:

  • KerberosAuthenticator : the authenticator implements the Kerberos SPNEGO authentication sequence.
  • PseudoAuthenticator : the authenticator implementation provides an authentication equivalent to Hadoop's Simple authentication, it trusts the value of the 'user.name' Java System property.

2. org.apache.hadoop.security.authentication.server.AuthenticationHandler: Interface for server authentication mechanisms.

  • KerberosAuthenticationHandler : the authenticator handler implements the Kerberos SPNEGO authentication mechanism for HTTP.
  • PseudoAuthenticationHandler : the authenticator handler provides a pseudo authentication mechanism that accepts the user name specified as a query string parameter.
  • AltKerberosAuthenticationHandler: the authenticator handler allows for Kerberos SPNEGO authentication for non-browsers and an alternate form of authentication for browsers. A subclass must implement the alternate authentication (see Example Login Server )

3. org.apache.hadoop.security.authentication.server.AuthenticationFilter: A servlet filter enables protecting web application resources with different authentication mechanisms provided by AuthenticationHandler. To enable the filter, web application resources file (ex. web.xml) needs to include a filter class derived from AuthenticationFilter .

Provide Custom Client Authenticator

In client side, a custom authentication requires a extended Authenticator to retrieve authentication token or certificate and set it to 'token' instance in method 'authenticate()'.

The following methods should be overridden by derived Authenticator.

   public void authenticate(URL url, AuthenticatedURL.Token token)
			throws IOException, AuthenticationException {
		TheAuthenticatorConf conf = TheAuthenticatorConf();
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setRequestMethod("OPTIONS");
		//Depending on actual authenticationovide Custom Authentication to Oozie Server
Eclipse and IntelliJ can use directly MiniOozie Maven project files. MiniOozie project can be imported to
Eclipse and IntelliJ as independent project.
overridden methods
<verbatim>
		 mechanism, retrieve the cert string or token.
		String encodedStr = URLEncoder.encode(aCertString, "UTF-8");
		// set to cookie with a key that can be recognized later in the server side.
		conn.addRequestProperty("Cookie", "NEWAUTH=" + encodedStr);
		// extract token from connection and set to token
		AuthenticatedURL.extractToken(conn, token);
	}

The following shows an example of a singleton class which can be used at a class of Authenticator to set and get configuration which is required for authentication purpose.

	public static class TheAuthenticatorConf {
		private static final TheAuthenticatorConf instance = new TheAuthenticatorConf();
		private final Map<String, String> map = new HashMap<String, String>();		private TheAuthenticatorConf() {
		}
		public static TheAuthenticatorConf getInstance() {
			return instance;
		}
		public void put(String key, String value) {
			map.put(key, value);
		}
		public String get(String key) {
			return map.get(key);
		}
		public void clear() {
			map.clear();
		}
	}

Provide Custom Authentication to Oozie Client

Apache Oozie contains a default class org.apache.oozie.client.AuthOozieClient to support Kerberos HTTP SPNEGO authentication, pseudo/simple authentication and anonymous access for client connections.

To provide other authentication mechanisms, a Oozie client should extend from AuthOozieClient and provide the following methods should be overridden by derived classes to provide custom authentication:

  • getAuthenticator() : return corresponding Authenticator based on value specified by user at auth command option.
  • createConnection() : create a singleton class at Authenticator to allow client set and get key-value configuration for authentication.

Provide Custom Server AuthenticationHandler

In server side, a custom authentication requires a extended AuthenticationHandler to retrieve authentication token or certificate from http request and verify it. After successful verification, an AuthenticationToken is created with user name and current authentication type. With this token, this request can be proceeded for response.

The following methods should be overridden by derived AuthenticationHandler.

    public AuthenticationToken authenticate(HttpServletRequest request, HttpServletResponse response)
            throws IOException, AuthenticationException {
		// the certificate or token can be retrieved from request and verified.
		// use the information from the legal certificate or token to create AuthenticationToken
        AuthenticationToken token = new AuthenticationToken(userName, principal, type);
        return token;
    }

Provide Custom Authentication to Oozie Server

To accept custom authentication in Oozie server, a filter extends from AuthenticationFilter must be provided. This filter delegates to the configured authentication handler for authentication and once it obtains an AuthenticationToken from it, sets a signed HTTP cookie with the token. If HTTP cookie is provided with different key name, its cookie value can be retrieved by overriding getToken() method. Please note, only when getToken() return NULL, a custom authentication can be invoked and processed in AuthenticationFilter.doFilter() .

The following method explains how to read it and return NULL token.

protected AuthenticationToken getToken(HttpServletRequest request) throws IOException, AuthenticationException {
        String tokenStr = null;
        Cookie[] cookies = request.getCookies();        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(AuthenticatedURL.AUTH_COOKIE)) {
                    tokenStr = cookie.getValue();
                    LOG.info("Got 'hadoop.auth' cookie from request = " + tokenStr);
                    if (tokenStr != null && !tokenStr.trim().isEmpty()) {
                        AuthenticationToken retToken = super.getToken(request);
                        return retToken;
                    }
                } else if (cookie.getName().equals("NEWAUTH")) {
                    tokenStr = cookie.getValue();
                    // DO NOT return the token string so request can authenticated.
                }
            }
        }
        return null;
      }

Login Server Example

Overview

The Login Server Example is a web application that is an example of how to create a login server for Oozie. It provides two example servlets: LoginServlet and LDAPLoginServlet. The LoginServlet example is very primitive and simply authenticates users whose username and password match (e.g. user=foo and pass=foo). The LDAPLoginServlet example can be configured against an LDAP server to authenticate users from that LDAP server. Once authenticated, both example servlets write the username to a cookie that Oozie checks via the ExampleAltAuthenticationHandler (which uses that cookie for authentication for browsers but Kerberos otherwise).

The LoginServlet and LDAPLoginServlet are run from a separate WAR file called oozie-login.war; its web.xml can be used to configure which servlet is used as well as some additional properties. The ExampleAltAuthenticationHandler is run as part of the Oozie server but is built as a separate jar: oozie-login.jar.

ExampleAltAuthenticationHandler

This is a subclass of the abstract AltKerberosAuthenticationHandler, which is an AuthenticationHandler that allows for a "mixed" mode of authentication. When a non-browser is used, Kerberos will be used for authentication; when a browser is used, some other authentication method will be used. In the case of ExampleAltAuthenticationHandler, the other authentication method is to look for a cookie named oozie.web.login.auth and create an AuthenticationToken using the value of the cookie as the username. If the cookie cannot be found, it will redirect the browser to a page where the user can (presumably) login to a server that can authenticate the user and create the cookie. As this is obviously a very primitive method of authentication that is not secure, it should NOT be used in production; it is only provided as an example of how the AltKerberosAuthenticationHandler can be used.

To reiterate: ExampleAltAuthenticationHandler IS NOT SECURE -- DO NOT USE IT IN A PRODUCTION ENVIRONMENT

To use the ExampleAltAuthenticationHandler, make at least the following two changes to your oozie-site.xml. All of the existing Kerberos-related settings are still applicable (for when a non-browser is used) so make sure to configure them appropriately.

   <property>
        <name>oozie.authentication.type</name>
        <value>org.apache.oozie.authentication.ExampleAltAuthenticationHandler</value>
   </property>
   <property>
        <name>oozie.service.HadoopAccessorService.kerberos.enabled</name>
        <value>true</value>
    </property>
Note: The ExampleAltAuthenticationHandler is included in the oozie-login.jar file and not normally included with Oozie core. Additionally, you can configure which user-agents AltKerberosAuthenticationHandler (and thus ExampleAltAuthenticationHandler) consider to be non-browsers by setting the following property in oozie-site.xml to a comma separated list. When any of the values in this property are contained in the user-agent of the request, Kerberos will be used; otherwise, the alternate authentication will be used.
   <property>
        <name>oozie.authentication.alt-kerberos.non-browser.user-agents</name>
        <value>java,curl,wget,perl</value>
   </property>
The above values, which are the default, will cause a user-agent such as "java" (the user-agent used by Java programs) to use Kerberos. Note that this would also match with user-agents such as "java6" and "I am not a JaVa program".

When the ExampleAltAuthenticationHandler cannot find the oozie.web.login.auth cookie, it will redirect the user to another URL, which can be configured by setting the following property in oozie-site.xml. Typically, this URL should take the user to a server where they can login to acquire the cookie and then get redirected back to the Oozie web console (the Login Server Example does this and will be explained in more detail later).

    <property>
        <name>oozie.authentication.ExampleAltAuthenticationHandler.redirect.url</name>
        <value>http://localhost:11000/oozie-login/?backurl={0}</value>
    </property>
The above value, which is the default, will cause the user to be redirected to the Login Server Example if its running in the same tomcat as Oozie and on the default port. If {0} appears anywhere in this URL, it will be replaced by the URL of Oozie's web console so that the Login Server Example can know where to send the user back while staying independent of Oozie.

LoginServlet

This is a web servlet that gets bundled in the oozie-login.war web application. It is a very primitive example of a login server implementation that is compatible with the ExampleAltAuthenticationHandler. When users visit this servlet, they are shown a simple login page that allows them to enter their username and password. It authenticates them if their username and password are the same (e.g. user=foo and pass=foo), which is not secure and should not be used in production; it is only provided as an example.

To reiterate: LoginServlet IS NOT SECURE -- DO NOT USE IT IN A PRODUCTION ENVIRONMENT

Sending it a GET request returns the login page; the backurl parameter is required (so it knows where to redirect the user back to once they are authenticated), but there is also an optional username parameter that will pre-populate the username field if given.

Sending it a POST request will also return the login page, but only if an error occurs (e.g. invalid username or password). As with the GET request, the backurl parameter is required, but now the username and password parameters are also required. If they match, the LoginServlet will write the oozie.web.login.auth cookie containing the username and redirect the user to the backurl , which is presumably the Oozie web console.

The login page can be configured to look differently by changing the following parameter in the web.xml in the oozie-login.war file (or in the login/src/main/webapp/WEB-INF/ directory before building it). The file needs to be located in the login/src/main/resources/ directory and should contain {0} for where an error message can go, {1} for where the username included with a GET request will go, and {2} for where the backurl goes.

    <init-param>
        <param-name>login.page.template</param-name>
        <param-value>login-page-template.html</param-value>
    </init-param>
The above value, which is the default, is a basic html page that has fields for the username and password and meets the previously stated requirements.

The oozie.web.login.auth cookie will expire 3 minutes after being given to the user. Once the user has been redirected back to the Oozie web console and given the AuthenticationToken, the oozie.web.login.auth cookie is no longer used. If the AuthenticationToken expires but the user still has a valid oozie.web.login.auth cookie, the ExampleAltAuthenticationHandler will simply give out a new AuthenticationToken; the desired behavior is that the user is bounced back to the oozie-login.war server to re-authenticate, hence the very short lifetime of the oozie.web.login.auth cookie. However, the expiration time of the cookie is configurable by changing the following parameter in the web.xml in the oozie-login.war file (or in the login/src/main/webapp/WEB-INF/ directory before building it). It is given in seconds. A positive value indicates that the cookie will expire after that many seconds have passed; make sure this value is high enough to allow the user to be forwarded to the backurl before the cookie expires. A negative value indicates that the cookie will be deleted when the browser exits.

    <init-param>
        <param-name>login.auth.cookie.expire.time</param-name>
        <param-value>180</param-value>
    </init-param>
The above value, which is the default, is the number of seconds in 3 minutes.

LDAPLoginServlet

This is a second web servlet that gets bundled in the oozie-login.war web application. It inherits from the LoginServlet, so the previous configuration information (e.g. login.page.template) still applies to this servlet. The only difference between the LDAPLoginServlet and the LoginServlet, is that the LDAPLoginServlet is configured against an LDAP server to provide the authentication instead of simply checking that the username and password are equal. As before, this is not secure and should not be used in production; it is only provided as an example.

To reiterate: LDAPLoginServlet IS NOT SECURE -- DO NOT USE IT IN A PRODUCTION ENVIRONMENT

The oozie-login.war web application is configured to use LoginServlet by default. To switch it to use the LDAPLoginServlet, you have to change the following line in the web.xml from:

    <servlet-class>org.apache.oozie.servlet.login.LoginServlet</servlet-class>
to:
    <servlet-class>org.apache.oozie.servlet.login.LDAPLoginServlet</servlet-class>

There are three additional parameters related to LDAP that you should configure in the web.xml:

    <init-param>
        <param-name>ldap.provider.url</param-name>
        <param-value>ldap://localhost:389</param-value>
    </init-param>
    <init-param>
        <param-name>ldap.context.factory</param-name>
        <param-value>com.sun.jndi.ldap.LdapCtxFactory</param-value>
    </init-param>
    <init-param>
        <param-name>ldap.security.authentication</param-name>
        <param-value>simple</param-value>
    </init-param>
The ldap.provider.url is the LDAP provider URL to use, the ldap.context.factory is the LDAP context factory to use, and the ldap.security.authentication is the LDAP security authentication type to use.

Building and Deploying

The README.txt file in the login directory contains instructions on how to build and deploy the Login Server Example

::Go back to Oozie Documentation Index::