/* Copyright 2006-2010 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 mx.edu.um.mateo.general.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import mx.edu.um.mateo.general.model.Usuario;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.switchuser.SwitchUserFilter;
import org.springframework.security.web.authentication.switchuser.SwitchUserGrantedAuthority;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
* Helper methods.
*
* @author <a href='mailto:burt@burtbeckwith.com'>Burt Beckwith</a>
*/
@SuppressWarnings("deprecation")
@Component
public class SpringSecurityUtils {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private RoleHierarchy roleHierarchy;
/**
* Default value for the name of the Ajax header.
*/
public static final String AJAX_HEADER = "X-Requested-With";
/**
* Used to ensure that all authenticated users have at least one granted
* authority to work around Spring Security code that assumes at least one.
* By granting this non-authority, the user can't do anything but gets past
* the somewhat arbitrary restrictions.
*/
public static final String NO_ROLE = "ROLE_NO_ROLES";
public SpringSecurityUtils() {
}
/**
* Extract the role names from authorities.
*
* @param authorities
* the authorities (a collection or array of
* {@link GrantedAuthority}).
* @return the names
*/
@SuppressWarnings("unchecked")
public static Set<String> authoritiesToRoles(final Object authorities) {
Set<String> roles = new HashSet<>();
for (GrantedAuthority authority : (Collection<GrantedAuthority>) authorities) {
String authorityName = authority.getAuthority();
if (null == authorityName) {
throw new IllegalArgumentException(
"Cannot process GrantedAuthority objects which return null from getAuthority() - attempting to process "
+ authority);
}
roles.add(authorityName);
}
return roles;
}
/**
* Get the current user's authorities.
*
* @return a list of authorities (empty if not authenticated).
*/
public static Collection<GrantedAuthority> getPrincipalAuthorities() {
Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication();
if (authentication == null) {
return Collections.emptyList();
}
@SuppressWarnings("unchecked")
Collection<GrantedAuthority> authorities = (Collection<GrantedAuthority>) authentication
.getAuthorities();
if (authorities == null) {
return Collections.emptyList();
}
// remove the fake role if it's there
Collection<GrantedAuthority> copy = new ArrayList<>(authorities);
for (Iterator<GrantedAuthority> iter = copy.iterator(); iter.hasNext();) {
if (iter.next().getAuthority().equals(NO_ROLE)) {
iter.remove();
}
}
return copy;
}
/**
* Split the role names and create {@link GrantedAuthority}s for each.
*
* @param roleNames
* comma-delimited role names
* @return authorities (possibly empty)
*/
public static List<GrantedAuthority> parseAuthoritiesString(
final String roleNames) {
List<GrantedAuthority> requiredAuthorities = new ArrayList<>();
for (String auth : StringUtils
.commaDelimitedListToStringArray(roleNames)) {
auth = auth.trim();
if (auth.length() > 0) {
requiredAuthorities.add(new GrantedAuthorityImpl(auth));
}
}
return requiredAuthorities;
}
/**
* Find authorities in <code>granted</code> that are also in
* <code>required</code>.
*
* @param granted
* the granted authorities (a collection or array of
* {@link SpringSecurityUtils}).
* @param required
* the required authorities (a collection or array of
* {@link SpringSecurityUtils}).
* @return the authority names
*/
public static Set<String> retainAll(final Object granted,
final Object required) {
Set<String> grantedRoles = authoritiesToRoles(granted);
Set<String> requiredRoles = authoritiesToRoles(required);
grantedRoles.retainAll(requiredRoles);
return grantedRoles;
}
/**
* Check if the current user has all of the specified roles.
*
* @param roles
* a comma-delimited list of role names
* @return <code>true</code> if the user is authenticated and has all the
* roles
*/
public boolean ifAllGranted(final String roles) {
Collection<GrantedAuthority> inferred = findInferredAuthorities(getPrincipalAuthorities());
return inferred.containsAll(parseAuthoritiesString(roles));
}
/**
* Check if the current user has none of the specified roles.
*
* @param roles
* a comma-delimited list of role names
* @return <code>true</code> if the user is authenticated and has none the
* roles
*/
public boolean ifNotGranted(final String roles) {
Collection<GrantedAuthority> inferred = findInferredAuthorities(getPrincipalAuthorities());
Set<String> grantedCopy = retainAll(inferred,
parseAuthoritiesString(roles));
return grantedCopy.isEmpty();
}
/**
* Check if the current user has any of the specified roles.
*
* @param roles
* a comma-delimited list of role names
* @return <code>true</code> if the user is authenticated and has any the
* roles
*/
public boolean ifAnyGranted(final String roles) {
Collection<GrantedAuthority> inferred = findInferredAuthorities(getPrincipalAuthorities());
Set<String> grantedCopy = retainAll(inferred,
parseAuthoritiesString(roles));
return !grantedCopy.isEmpty();
}
/**
* Check if the current user is switched to another user.
*
* @return <code>true</code> if logged in and switched
*/
public boolean isSwitched() {
return ifAllGranted(SwitchUserFilter.ROLE_PREVIOUS_ADMINISTRATOR);
}
/**
* Get the username of the original user before switching to another.
*
* @return the original login name
*/
public String getSwitchedUserOriginalUsername() {
if (isSwitched()) {
Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication();
for (GrantedAuthority auth : authentication.getAuthorities()) {
if (auth instanceof SwitchUserGrantedAuthority) {
return ((SwitchUserGrantedAuthority) auth).getSource()
.getName();
}
}
}
return null;
}
/**
* Rebuild an Authentication for the given username and register it in the
* security context. Typically used after updating a user's authorities or
* other auth-cached info.
* <p/>
* Also removes the user from the user cache to force a refresh at next
* login.
*
* @param username
* the user's login name
* @param password
* optional
*/
public void reauthenticate(final String username, final String password) {
UserDetails userDetails = userDetailsService
.loadUserByUsername(username);
SecurityContextHolder.getContext()
.setAuthentication(
new UsernamePasswordAuthenticationToken(userDetails,
password == null ? userDetails.getPassword()
: password, userDetails
.getAuthorities()));
}
private Collection<GrantedAuthority> findInferredAuthorities(
final Collection<GrantedAuthority> granted) {
@SuppressWarnings("unchecked")
Collection<GrantedAuthority> reachable = (Collection<GrantedAuthority>) roleHierarchy
.getReachableGrantedAuthorities(granted);
if (reachable == null) {
return Collections.emptyList();
}
return reachable;
}
public Usuario obtieneUsuario() {
Usuario usuario = (Usuario) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
return usuario;
}
}