/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright 2016 Pentaho Corporation. All rights reserved. */ package org.pentaho.platform.osgi; import java.io.IOException; import java.security.Principal; import java.util.Collection; import java.util.HashSet; 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.LoginException; import org.apache.karaf.jaas.boot.principal.RolePrincipal; import org.apache.karaf.jaas.boot.principal.UserPrincipal; import org.apache.karaf.jaas.modules.AbstractKarafLoginModule; import org.pentaho.platform.api.engine.IAuthorizationPolicy; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.core.system.StandaloneSession; import org.pentaho.platform.engine.security.SecurityHelper; import org.pentaho.platform.security.policy.rolebased.actions.AdministerSecurityAction; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; /** * JAAS LoginModule which delegates to the Platform's Spring Security * {@link org.springframework.security.AuthenticationManager}. * * If the Authenticated user has AdministerSecurity permissions, they'll be given a synthetic role of "karaf_admin" * which provides access to Admin features of Karaf * * Created by nbaker on 8/26/14. */ public class SpringSecurityLoginModule extends AbstractKarafLoginModule { public static final String KARAF_ADMIN = "karaf_admin"; private AuthenticationManager authenticationManager = null; private IAuthorizationPolicy authorizationPolicy = null; public SpringSecurityLoginModule() { } public AuthenticationManager getAuthenticationManager() { if ( authenticationManager == null ) { authenticationManager = PentahoSystem.get( AuthenticationManager.class ); } return authenticationManager; } public IAuthorizationPolicy getAuthorizationPolicy() { if ( authorizationPolicy == null ) { authorizationPolicy = PentahoSystem.get( IAuthorizationPolicy.class ); } return authorizationPolicy; } public void setAuthenticationManager( AuthenticationManager authenticationManager ) { this.authenticationManager = authenticationManager; } public void setAuthorizationPolicy( IAuthorizationPolicy authorizationPolicy ) { this.authorizationPolicy = authorizationPolicy; } public void initialize( Subject sub, CallbackHandler handler, Map sharedState, Map options ) { super.initialize( sub, handler, options ); } public boolean login() throws LoginException { org.springframework.security.core.Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if ( authentication != null ) { // Obtain the username of the incoming auth request to match against existing authentication on the thread. Callback[] callbacks = new Callback[1]; callbacks[0] = new NameCallback( "User: " ); try { callbackHandler.handle( callbacks ); } catch ( IOException e ) { throw new LoginException( e.getMessage() ); } catch ( UnsupportedCallbackException e ) { throw new LoginException( "Unable to interactively Authenticate with user: " + e.getMessage() ); } // user callback get value String name = ( (NameCallback) callbacks[0] ).getName(); if ( name == null ) { throw new LoginException( "User name is null" ); } // If the existing thread-bound authentication does not match, discard it. if ( !name.equals( authentication.getName() ) ) { // reauthenticate authentication = null; } } if ( authentication == null ) { Callback[] callbacks = new Callback[2]; callbacks[0] = new NameCallback( "User: " ); callbacks[1] = new PasswordCallback( "Password: ", false ); try { callbackHandler.handle( callbacks ); } catch ( IOException e ) { throw new LoginException( e.getMessage() ); } catch ( UnsupportedCallbackException e ) { throw new LoginException( "Unable to interactively Authenticate with user: " + e.getMessage() ); } String name = ( (NameCallback) callbacks[0] ).getName(); char[] password1 = ( (PasswordCallback) callbacks[1] ).getPassword(); if ( password1 == null || name == null ) { throw new LoginException( "User Name and Password cannot be null" ); } String password = new String( password1 ); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( name, String.valueOf( password ) ); IPentahoSession session = new StandaloneSession( name ); PentahoSessionHolder.setSession( session ); try { // Throws an exception on failure. authentication = getAuthenticationManager().authenticate( token ); if ( authentication != null && !authentication.isAuthenticated() ) { throw new IllegalStateException( "Got a bad authentication" ); } if ( authentication == null ) { throw new IllegalStateException( "Not Authenticated" ); } } catch ( Exception e ) { session.destroy(); PentahoSessionHolder.removeSession(); throw new LoginException( e.getMessage() ); } } principals = new HashSet<Principal>(); principals.add( new UserPrincipal( authentication.getName() ) ); Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); if ( authorities != null ) { for ( GrantedAuthority authority : authorities ) { principals.add( new RolePrincipal( authority.getAuthority() ) ); } } // AuthorizationPolicy requires a PentahoSession. becomeUSer is the easiest way SecurityHelper.getInstance().becomeUser( authentication.getName() ); // If they have AdministerSecurity, grant the Karaf admin role if ( getAuthorizationPolicy().isAllowed( AdministerSecurityAction.NAME ) ) { principals.add( new RolePrincipal( KARAF_ADMIN ) ); } return true; } public boolean abort() throws LoginException { clear(); return true; } public boolean logout() throws LoginException { subject.getPrincipals().removeAll( principals ); principals.clear(); return true; } }