/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License, version 2 as published by the Free Software * Foundation. * * You should have received a copy of the GNU General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.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 General Public License for more details. * * * Copyright 2006 - 2016 Pentaho Corporation. All rights reserved. */ package org.pentaho.platform.engine.security; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.platform.api.engine.security.IAuthenticationRoleMapper; import org.springframework.dao.DataAccessException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.util.Assert; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; /** * Decorates another {@link UserDetailsService} and returns a proxy during * {@link UserDetailsService#loadUserByUsername(String)}. The proxy an extra role when * {@link UserDetails#getAuthorities()} is called. * * <p> * This class is only necessary for {@link UserDetailsService} implementations that don't allow you to supply a * default role (e.g. {@code LdapUserDetailsService}). * </p> * * Use with {@code ExtraRolesUserRoleListServiceDecorator}. * * @author mlowery */ public class DefaultRoleUserDetailsServiceDecorator implements UserDetailsService { // ~ Static fields/initializers // ====================================================================================== private static final Log logger = LogFactory.getLog( DefaultRoleUserDetailsServiceDecorator.class ); // ~ Instance fields // ================================================================================================= private UserDetailsService userDetailsService; private GrantedAuthority defaultRole; private IAuthenticationRoleMapper roleMapper; // ~ Constructors // ==================================================================================================== public DefaultRoleUserDetailsServiceDecorator() { super(); } // ~ Methods // ========================================================================================================= public UserDetails loadUserByUsername( final String username ) throws UsernameNotFoundException, DataAccessException { if ( logger.isDebugEnabled() ) { logger.debug( "injecting proxy" ); //$NON-NLS-1$ } UserDetails userDetails = userDetailsService.loadUserByUsername( username ); return getUserDetailsWithDefaultRole( userDetails ); } protected UserDetails getUserDetailsWithDefaultRole( final UserDetails userDetails ) { if ( defaultRole != null ) { return new DefaultRoleUserDetailsProxy( userDetails, defaultRole, roleMapper ); } else { return userDetails; } } public void setUserDetailsService( final UserDetailsService userDetailsService ) { Assert.notNull( userDetailsService ); this.userDetailsService = userDetailsService; } public void setDefaultRole( final String defaultRole ) { Assert.notNull( defaultRole ); this.defaultRole = new SimpleGrantedAuthority( defaultRole ); } public void setRoleMapper( final IAuthenticationRoleMapper roleMapper ) { this.roleMapper = roleMapper; } /** * A {@link UserDetails} that has an extra role. The extra role is added to the end of the original role list and * only if it is not already in the original role list. * * @author mlowery */ public static class DefaultRoleUserDetailsProxy implements UserDetails { // ~ Static fields/initializers // ==================================================================================== // ~ Instance fields // =============================================================================================== private static final long serialVersionUID = -4262518338443465424L; private UserDetails userDetails; private Collection<? extends GrantedAuthority> newRoles; private IAuthenticationRoleMapper roleMapper; // ~ Constructors // ================================================================================================== public DefaultRoleUserDetailsProxy( final UserDetails userDetails, final GrantedAuthority defaultRole ) { this( userDetails, defaultRole, null ); } public DefaultRoleUserDetailsProxy( final UserDetails userDetails, final GrantedAuthority defaultRole, final IAuthenticationRoleMapper roleMapper ) { super(); Assert.notNull( userDetails ); Assert.notNull( defaultRole ); this.userDetails = userDetails; this.roleMapper = roleMapper; newRoles = getNewRoles( defaultRole ); } // ~ Methods // ======================================================================================================= /** * Since UserDetails is immutable, we can safely pre-calculate the new roles. */ protected Collection<? extends GrantedAuthority> getNewRoles( final GrantedAuthority defaultRole ) { Collection<? extends GrantedAuthority> origRoles = userDetails.getAuthorities(); List<GrantedAuthority> newRoles1 = new ArrayList<GrantedAuthority>(); // Map Non-pentaho roles to pentaho roles. This mapping is defined in the // applicationContext-spring-security-ldap.xml if ( roleMapper != null ) { for ( GrantedAuthority authority : origRoles ) { newRoles1.add( new SimpleGrantedAuthority( roleMapper.toPentahoRole( authority.getAuthority() ) ) ); } } if ( !origRoles.contains( defaultRole ) ) { if ( logger.isDebugEnabled() ) { logger .debug( "adding defaultRole=" + defaultRole + " to list of roles for username=" + userDetails.getUsername() ); //$NON-NLS-1$ //$NON-NLS-2$ } newRoles1.add( defaultRole ); } return newRoles1; } public Collection<? extends GrantedAuthority> getAuthorities() { return newRoles; } public String getPassword() { return userDetails.getPassword(); } public String getUsername() { return userDetails.getUsername(); } public boolean isAccountNonExpired() { return userDetails.isAccountNonExpired(); } public boolean isAccountNonLocked() { return userDetails.isAccountNonLocked(); } public boolean isCredentialsNonExpired() { return userDetails.isCredentialsNonExpired(); } public boolean isEnabled() { return userDetails.isEnabled(); } } }