/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2013 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * 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 org.pentaho.di.core.auth.kerberos; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.AppConfigurationEntry; import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag; import javax.security.auth.login.Configuration; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import com.sun.security.auth.module.Krb5LoginModule; public class KerberosUtil { /** * A Login Configuration that is pre-configured based on our static configuration. */ public static class PentahoLoginConfiguration extends Configuration { private AppConfigurationEntry[] entries; public PentahoLoginConfiguration( AppConfigurationEntry[] entries ) { if ( entries == null ) { throw new NullPointerException( "AppConfigurationEntry[] is required" ); } this.entries = entries; } @Override public AppConfigurationEntry[] getAppConfigurationEntry( String ignored ) { return entries; } } /** * The application name to use when creating login contexts. */ public static final String KERBEROS_APP_NAME = "pentaho"; /** * The environment property to set to enable JAAS debugging for the LoginConfiguration created by this utility. */ public static final String PENTAHO_JAAS_DEBUG = "PENTAHO_JAAS_DEBUG"; /** * Base properties to be inherited by all other LOGIN_CONFIG* configuration maps. */ public static final Map<String, String> LOGIN_CONFIG_BASE = createLoginConfigBaseMap(); /** * Login Configuration options for KERBEROS_USER mode. */ private static final Map<String, String> LOGIN_CONFIG_OPTS_KERBEROS_USER = getLoginConfigOptsKerberosUser(); private static final Map<String, String> LOGIN_CONFIG_OPTS_KERBEROS_USER_NOPASS = getLoginConfigOptsKerberosNoPassword(); private static Map<String, String> createLoginConfigBaseMap() { Map<String, String> result = new HashMap<String, String>(); // Enable JAAS debug if PENTAHO_JAAS_DEBUG is set if ( Boolean.parseBoolean( System.getenv( PENTAHO_JAAS_DEBUG ) ) ) { result.put( "debug", Boolean.TRUE.toString() ); } return Collections.unmodifiableMap( result ); } private static Map<String, String> getLoginConfigOptsKerberosUser() { Map<String, String> result = new HashMap<String, String>( LOGIN_CONFIG_BASE ); result.put( "useTicketCache", Boolean.FALSE.toString() ); // Attempt to renew tickets result.put( "renewTGT", Boolean.FALSE.toString() ); return Collections.unmodifiableMap( result ); } private static Map<String, String> getLoginConfigOptsKerberosNoPassword() { Map<String, String> result = new HashMap<String, String>( LOGIN_CONFIG_OPTS_KERBEROS_USER ); result.put( "useTicketCache", Boolean.TRUE.toString() ); result.put( "renewTGT", Boolean.TRUE.toString() ); // Never prompt for passwords result.put( "doNotPrompt", Boolean.TRUE.toString() ); return result; } /** * Login Configuration options for KERBEROS_KEYTAB mode. */ public static final Map<String, String> LOGIN_CONFIG_OPTS_KERBEROS_KEYTAB = createLoginConfigOptsKerberosKeytabMap(); private static Map<String, String> createLoginConfigOptsKerberosKeytabMap() { Map<String, String> result = new HashMap<String, String>( LOGIN_CONFIG_BASE ); // Never prompt for passwords result.put( "doNotPrompt", Boolean.TRUE.toString() ); // Use a keytab file result.put( "useKeyTab", Boolean.TRUE.toString() ); result.put( "storeKey", Boolean.TRUE.toString() ); // Refresh KRB5 config before logging in result.put( "refreshKrb5Config", Boolean.TRUE.toString() ); return Collections.unmodifiableMap( result ); } public LoginContext getLoginContextFromKeytab( String principal, String keytab ) throws LoginException { Map<String, String> keytabConfig = new HashMap<String, String>( LOGIN_CONFIG_OPTS_KERBEROS_KEYTAB ); keytabConfig.put( "keyTab", keytab ); keytabConfig.put( "principal", principal ); // Create the configuration and from them, a new login context AppConfigurationEntry config = new AppConfigurationEntry( Krb5LoginModule.class.getName(), LoginModuleControlFlag.REQUIRED, keytabConfig ); AppConfigurationEntry[] configEntries = new AppConfigurationEntry[] { config }; Subject subject = new Subject(); return new LoginContext( KERBEROS_APP_NAME, subject, null, new PentahoLoginConfiguration( configEntries ) ); } public LoginContext getLoginContextFromUsernamePassword( final String principal, final String password ) throws LoginException { Map<String, String> opts = new HashMap<String, String>( LOGIN_CONFIG_OPTS_KERBEROS_USER ); opts.put( "principal", principal ); AppConfigurationEntry[] appConfigurationEntries = new AppConfigurationEntry[] { new AppConfigurationEntry( Krb5LoginModule.class.getName(), LoginModuleControlFlag.REQUIRED, opts ) }; return new LoginContext( KERBEROS_APP_NAME, new Subject(), new CallbackHandler() { @Override public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException { for ( Callback callback : callbacks ) { if ( callback instanceof NameCallback ) { ( (NameCallback) callback ).setName( principal ); } else if ( callback instanceof PasswordCallback ) { ( (PasswordCallback) callback ).setPassword( password.toCharArray() ); } else { throw new UnsupportedCallbackException( callback ); } } } }, new PentahoLoginConfiguration( appConfigurationEntries ) ); } public LoginContext getLoginContextFromKerberosCache( String principal ) throws LoginException { Map<String, String> opts = new HashMap<String, String>( LOGIN_CONFIG_OPTS_KERBEROS_USER_NOPASS ); opts.put( "principal", principal ); AppConfigurationEntry[] appConfigurationEntries = new AppConfigurationEntry[] { new AppConfigurationEntry( Krb5LoginModule.class.getName(), LoginModuleControlFlag.REQUIRED, opts ) }; return new LoginContext( KERBEROS_APP_NAME, new Subject(), null, new PentahoLoginConfiguration( appConfigurationEntries ) ); } }