/**
* Copyright (c) 2013-2016, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.seedstack.seed.security.internal;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.pam.UnsupportedTokenException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.seedstack.seed.security.PrincipalCustomizer;
import org.seedstack.seed.security.Realm;
import org.seedstack.seed.security.Role;
import org.seedstack.seed.security.internal.authorization.SeedAuthorizationInfo;
import org.seedstack.seed.security.internal.realms.AuthenticationTokenWrapper;
import org.seedstack.seed.security.principals.PrincipalProvider;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
class ShiroRealmAdapter extends AuthorizingRealm {
private Realm realm;
@SuppressWarnings("rawtypes")
@Inject
private Set<PrincipalCustomizer> principalCustomizers;
@Override
public AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
return super.getAuthorizationInfo(principals);
}
@SuppressWarnings("unchecked")
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SeedAuthorizationInfo authzInfo = new SeedAuthorizationInfo();
PrincipalProvider<?> idPrincipal = (PrincipalProvider<?>) principals.getPrimaryPrincipal();
Collection<PrincipalProvider<?>> principalProviders = new ArrayList<>();
principalProviders.add(idPrincipal);
for (Object principal : principals) {
if (principal instanceof PrincipalProvider) {
principalProviders.add((PrincipalProvider<?>) principal);
}
}
List<PrincipalProvider<?>> asList = principals.asList();
for (Role role : realm.getRoleMapping().resolveRoles(realm.getRealmRoles(idPrincipal, asList), principalProviders)) {
role.getPermissions().addAll(realm.getRolePermissionResolver().resolvePermissionsInRole(role));
authzInfo.addRole(role);
}
return authzInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(final AuthenticationToken token) throws AuthenticationException {
org.seedstack.seed.security.AuthenticationToken seedToken = convertToken(token);
if (seedToken == null) {
throw new UnsupportedTokenException("The token " + token.getClass() + " is not supported");
}
org.seedstack.seed.security.AuthenticationInfo apiAuthenticationInfo;
try {
apiAuthenticationInfo = realm.getAuthenticationInfo(seedToken);
} catch (org.seedstack.seed.security.IncorrectCredentialsException e) {
throw new IncorrectCredentialsException(e);
} catch (org.seedstack.seed.security.UnknownAccountException e) {
throw new UnknownAccountException(e);
} catch (org.seedstack.seed.security.UnsupportedTokenException e) {
throw new UnsupportedTokenException(e);
} catch (org.seedstack.seed.security.AuthenticationException e) {
throw new AuthenticationException(e);
}
SimpleAuthenticationInfo authcInfo = new SimpleAuthenticationInfo();
SimplePrincipalCollection principals = new SimplePrincipalCollection(apiAuthenticationInfo.getIdentityPrincipal(), this.getName());
authcInfo.setCredentials(token.getCredentials());
//Realm principals
for (PrincipalProvider<?> principal : apiAuthenticationInfo.getOtherPrincipals()) {
principals.add(principal, this.getName());
}
//Custom principals
for (PrincipalCustomizer<?> principalCustomizer : principalCustomizers) {
if (principalCustomizer.supportedRealm().isAssignableFrom(getRealm().getClass())) {
for (PrincipalProvider<?> principal : principalCustomizer.principalsToAdd(apiAuthenticationInfo.getIdentityPrincipal(), apiAuthenticationInfo.getOtherPrincipals())) {
principals.add(principal, this.getName());
}
}
}
authcInfo.setPrincipals(principals);
return authcInfo;
}
Realm getRealm() {
return realm;
}
void setRealm(Realm realm) {
this.realm = realm;
}
@Override
public boolean supports(AuthenticationToken token) {
org.seedstack.seed.security.AuthenticationToken seedToken = convertToken(token);
return seedToken != null && realm.supportedToken().isAssignableFrom(seedToken.getClass());
}
private org.seedstack.seed.security.AuthenticationToken convertToken(AuthenticationToken token) {
if (token instanceof UsernamePasswordToken) {
UsernamePasswordToken shiroToken = (UsernamePasswordToken) token;
return new org.seedstack.seed.security.UsernamePasswordToken(shiroToken.getUsername(), shiroToken.getPassword());
} else if (token instanceof AuthenticationTokenWrapper) {
AuthenticationTokenWrapper shiroToken = (AuthenticationTokenWrapper) token;
return shiroToken.getSeedToken();
} else {
return null;
}
}
}