com.redhat.tools.kerberos.SunJaasKerberosTicketValidator.java Source code

Java tutorial

Introduction

Here is the source code for com.redhat.tools.kerberos.SunJaasKerberosTicketValidator.java

Source

/*
 * Copyright 2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.redhat.tools.kerberos;

/*
 * Copyright 2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.net.URL;
import java.security.Principal;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSManager;

/**
 * This class Uses the SUN JAAS login module, which is included in the SUN JRE,
 * it will not work with an IBM JRE. The whole configuration is done in this
 * class, no additional JAAS configuration is needed.
 * 
 * @author ligangty@gmail.com
 * @since 1.0
 * @version $Id$
 */
public class SunJaasKerberosTicketValidator {

    private String servicePrincipal = "Your server principle";
    private String keyTabLocation = "Your server keytab file location";
    private Subject serviceSubject;
    private boolean debug = false;
    private static final Log LOG = LogFactory.getLog(SunJaasKerberosTicketValidator.class);

    public SunJaasKerberosTicketValidator() {
        try {
            setProperties();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.springframework.security.extensions.kerberos.KerberosTicketValidator
     * #validateTicket(byte[])
     */
    public String validateTicket(byte[] token) {
        String username = null;
        try {
            username = Subject.doAs(this.serviceSubject, new KerberosValidateAction(token));
        } catch (PrivilegedActionException e) {
            e.printStackTrace();
        }
        return username;
    }

    /**
     * The service principal of the application. For web apps this is
     * <code>HTTP/full-qualified-domain-name@DOMAIN</code>. The keytab must
     * contain the key for this principal.
     * 
     * @param servicePrincipal
     *            service principal to use
     * @see #setKeyTabLocation(Resource)
     */
    public void setServicePrincipal(String servicePrincipal) {
        this.servicePrincipal = servicePrincipal;
    }

    /**
     * The location of the keytab. You can use the normale Spring Resource
     * prefixes like <code>file:</code> or <code>classpath:</code>, but as the
     * file is later on read by JAAS, we cannot guarantee that
     * <code>classpath</code> works in every environment, esp. not in Java EE
     * application servers. You should use <code>file:</code> there.<br />
     * <br />
     * This file also needs special protection, which is another reason to not
     * include it in the classpath but rather use
     * <code>file:/etc/http.keytab</code> for example.
     * 
     * @param keyTabLocation
     *            The location where the keytab resides
     */
    public void setKeyTabLocation(String keyTabLocation) {
        this.keyTabLocation = keyTabLocation;
    }

    /**
     * Enables the debug mode of the JAAS Kerberos login module
     * 
     * @param debug
     *            default is false
     */
    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    public void setProperties() throws Exception {
        // if (keyTabLocation instanceof ClassPathResource) {
        // LOG.warn("Your keytab is in the classpath. This file needs special protection and shouldn't be in the classpath. JAAS may also not be able to load this file from classpath.");
        // }
        URL keytabURL = new URL(this.keyTabLocation);
        LoginConfig loginConfig = new LoginConfig(keytabURL.toExternalForm(), this.servicePrincipal, this.debug);
        Set<Principal> princ = new HashSet<Principal>(1);
        princ.add(new KerberosPrincipal(this.servicePrincipal));
        Subject sub = new Subject(false, princ, new HashSet<Object>(), new HashSet<Object>());
        LoginContext lc = new LoginContext("", sub, null, loginConfig);
        lc.login();
        this.serviceSubject = lc.getSubject();
    }

    /**
     * This class is needed, because the validation must run with previously
     * generated JAAS subject which belongs to the service principal and was
     * loaded out of the keytab during startup.
     * 
     * @author Mike Wiesner
     * @since 1.0
     */
    private static class KerberosValidateAction implements PrivilegedExceptionAction<String> {
        byte[] kerberosTicket;

        public KerberosValidateAction(byte[] kerberosTicket) {
            this.kerberosTicket = kerberosTicket;
        }

        @Override
        public String run() throws Exception {
            GSSContext context = GSSManager.getInstance().createContext((GSSCredential) null);
            System.out.println("key in gss:" + kerberosTicket);
            context.acceptSecContext(kerberosTicket, 0, kerberosTicket.length);
            String user = context.getSrcName().toString();
            context.dispose();
            return user;
        }

    }

    /**
     * Normally you need a JAAS config file in order to use the JAAS Kerberos
     * Login Module, with this class it is not needed and you can have different
     * configurations in one JVM.
     * 
     * @author Mike Wiesner
     * @since 1.0
     */
    private static class LoginConfig extends Configuration {
        private String keyTabLocation;
        private String servicePrincipalName;
        private boolean debug;

        public LoginConfig(String keyTabLocation, String servicePrincipalName, boolean debug) {
            this.keyTabLocation = keyTabLocation;
            this.servicePrincipalName = servicePrincipalName;
            this.debug = debug;
        }

        @Override
        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
            HashMap<String, String> options = new HashMap<String, String>();
            options.put("useKeyTab", "true");
            options.put("keyTab", this.keyTabLocation);
            options.put("principal", this.servicePrincipalName);
            options.put("storeKey", "true");
            options.put("doNotPrompt", "true");
            if (this.debug) {
                options.put("debug", "true");
            }
            options.put("isInitiator", "false");

            return new AppConfigurationEntry[] {
                    new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
                            AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options), };
        }

    }

}