org.usergrid.security.shiro.Realm Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of usergrid-services Show documentation
Show all versions of usergrid-services Show documentation
Service layer for Usergrid system.
/*******************************************************************************
* Copyright 2012 Apigee Corporation
*
* 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.usergrid.security.shiro;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.usergrid.management.AccountCreationProps.PROPERTIES_SYSADMIN_LOGIN_ALLOWED;
import static org.usergrid.persistence.cassandra.CassandraService.MANAGEMENT_APPLICATION_ID;
import static org.usergrid.security.shiro.utils.SubjectUtils.getPermissionFromPath;
import static org.usergrid.utils.StringUtils.stringOrSubstringAfterFirst;
import static org.usergrid.utils.StringUtils.stringOrSubstringBeforeFirst;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.permission.PermissionResolver;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.usergrid.management.AccountCreationProps;
import org.usergrid.management.ApplicationInfo;
import org.usergrid.management.ManagementService;
import org.usergrid.management.OrganizationInfo;
import org.usergrid.management.UserInfo;
import org.usergrid.persistence.Entity;
import org.usergrid.persistence.EntityManager;
import org.usergrid.persistence.EntityManagerFactory;
import org.usergrid.persistence.Results;
import org.usergrid.persistence.Results.Level;
import org.usergrid.persistence.SimpleEntityRef;
import org.usergrid.persistence.entities.Role;
import org.usergrid.persistence.entities.User;
import org.usergrid.security.shiro.credentials.AccessTokenCredentials;
import org.usergrid.security.shiro.credentials.AdminUserAccessToken;
import org.usergrid.security.shiro.credentials.AdminUserPassword;
import org.usergrid.security.shiro.credentials.ApplicationAccessToken;
import org.usergrid.security.shiro.credentials.ApplicationUserAccessToken;
import org.usergrid.security.shiro.credentials.ClientCredentials;
import org.usergrid.security.shiro.credentials.OrganizationAccessToken;
import org.usergrid.security.shiro.credentials.PrincipalCredentials;
import org.usergrid.security.shiro.principals.AdminUserPrincipal;
import org.usergrid.security.shiro.principals.ApplicationGuestPrincipal;
import org.usergrid.security.shiro.principals.ApplicationPrincipal;
import org.usergrid.security.shiro.principals.ApplicationUserPrincipal;
import org.usergrid.security.shiro.principals.OrganizationPrincipal;
import org.usergrid.security.shiro.principals.PrincipalIdentifier;
import org.usergrid.security.tokens.TokenInfo;
import org.usergrid.security.tokens.TokenService;
import com.google.common.collect.HashBiMap;
public class Realm extends AuthorizingRealm {
private static final Logger logger = LoggerFactory.getLogger(Realm.class);
public final static String ROLE_SERVICE_ADMIN = "service-admin";
public final static String ROLE_ADMIN_USER = "admin-user";
public final static String ROLE_ORGANIZATION_ADMIN = "organization-admin";
public final static String ROLE_APPLICATION_ADMIN = "application-admin";
public final static String ROLE_APPLICATION_USER = "application-user";
private EntityManagerFactory emf;
private ManagementService management;
private TokenService tokens;
@Value("${"+PROPERTIES_SYSADMIN_LOGIN_ALLOWED+"}")
private boolean superUserEnabled;
@Value("${"+AccountCreationProps.PROPERTIES_SYSADMIN_LOGIN_NAME+":admin}")
private String superUser;
public Realm() {
setCredentialsMatcher(new AllowAllCredentialsMatcher());
setPermissionResolver(new CustomPermissionResolver());
}
public Realm(CacheManager cacheManager) {
super(cacheManager);
setCredentialsMatcher(new AllowAllCredentialsMatcher());
setPermissionResolver(new CustomPermissionResolver());
}
public Realm(CredentialsMatcher matcher) {
super(new AllowAllCredentialsMatcher());
setPermissionResolver(new CustomPermissionResolver());
}
public Realm(CacheManager cacheManager, CredentialsMatcher matcher) {
super(cacheManager, new AllowAllCredentialsMatcher());
setPermissionResolver(new CustomPermissionResolver());
}
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
if (!(credentialsMatcher instanceof AllowAllCredentialsMatcher)) {
logger.debug("Replacing {} with AllowAllCredentialsMatcher", credentialsMatcher);
credentialsMatcher = new AllowAllCredentialsMatcher();
}
super.setCredentialsMatcher(credentialsMatcher);
}
@Override
public void setPermissionResolver(PermissionResolver permissionResolver) {
if (!(permissionResolver instanceof CustomPermissionResolver)) {
logger.debug("Replacing {} with AllowAllCredentialsMatcher", permissionResolver);
permissionResolver = new CustomPermissionResolver();
}
super.setPermissionResolver(permissionResolver);
}
@Autowired
public void setEntityManagerFactory(EntityManagerFactory emf) {
this.emf = emf;
}
@Autowired
public void setManagementService(ManagementService management) {
this.management = management;
}
@Autowired
public void setTokenService(TokenService tokens) {
this.tokens = tokens;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
PrincipalCredentialsToken pcToken = (PrincipalCredentialsToken) token;
if (pcToken.getCredentials() == null) {
throw new CredentialsException("Missing credentials");
}
boolean authenticated = false;
PrincipalIdentifier principal = pcToken.getPrincipal();
PrincipalCredentials credentials = pcToken.getCredentials();
if (credentials instanceof ClientCredentials) {
authenticated = true;
} else if ((principal instanceof AdminUserPrincipal)
&& (credentials instanceof AdminUserPassword)) {
authenticated = true;
} else if ((principal instanceof AdminUserPrincipal)
&& (credentials instanceof AdminUserAccessToken)) {
authenticated = true;
} else if ((principal instanceof ApplicationUserPrincipal)
&& (credentials instanceof ApplicationUserAccessToken)) {
authenticated = true;
} else if ((principal instanceof ApplicationPrincipal)
&& (credentials instanceof ApplicationAccessToken)) {
authenticated = true;
} else if ((principal instanceof OrganizationPrincipal)
&& (credentials instanceof OrganizationAccessToken)) {
authenticated = true;
}
if (principal != null) {
if (!principal.isActivated()) {
throw new AuthenticationException("Unactivated identity");
}
if (principal.isDisabled()) {
throw new AuthenticationException("Disabled identity");
}
}
if (!authenticated) {
throw new AuthenticationException("Unable to authenticate");
}
logger.debug("Authenticated: {}", principal);
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
pcToken.getPrincipal(), pcToken.getCredentials(), getName());
return info;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Map organizationSet = HashBiMap.create();
Map applicationSet = HashBiMap.create();
OrganizationInfo organization = null;
ApplicationInfo application = null;
for (PrincipalIdentifier principal : principals
.byType(PrincipalIdentifier.class)) {
if (principal instanceof OrganizationPrincipal) {
// OrganizationPrincipals are usually only through OAuth
// They have access to a single organization
organization = ((OrganizationPrincipal) principal)
.getOrganization();
role(info, principal, ROLE_ORGANIZATION_ADMIN);
role(info, principal, ROLE_APPLICATION_ADMIN);
grant(info, principal,
"organizations:access:" + organization.getUuid());
organizationSet.put(organization.getUuid(),
organization.getName());
Map applications = null;
try {
applications = management
.getApplicationsForOrganization(organization
.getUuid());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if ((applications != null) && !applications.isEmpty()) {
grant(info,
principal,
"applications:admin,access,get,put,post,delete:"
+ StringUtils.join(applications.keySet(),
','));
applicationSet.putAll(applications);
}
} else if (principal instanceof ApplicationPrincipal) {
// ApplicationPrincipal are usually only through OAuth
// They have access to a single application
role(info, principal, ROLE_APPLICATION_ADMIN);
application = ((ApplicationPrincipal) principal)
.getApplication();
grant(info, principal,
"applications:admin,access,get,put,post,delete:"
+ application.getId());
applicationSet.put(application.getId(), application.getName());
} else if (principal instanceof AdminUserPrincipal) {
// AdminUserPrincipals are through basic auth and sessions
// They have access to organizations and organization
// applications
UserInfo user = ((AdminUserPrincipal) principal).getUser();
if (superUserEnabled && (superUser != null)
&& superUser.equals(user.getUsername())) {
// The system user has access to everything
role(info, principal, ROLE_SERVICE_ADMIN);
role(info, principal, ROLE_ORGANIZATION_ADMIN);
role(info, principal, ROLE_APPLICATION_ADMIN);
role(info, principal, ROLE_ADMIN_USER);
grant(info, principal, "system:access");
grant(info, principal,
"organizations:admin,access,get,put,post,delete:*");
grant(info, principal,
"applications:admin,access,get,put,post,delete:*");
grant(info, principal,
"organizations:admin,access,get,put,post,delete:*:/**");
grant(info, principal,
"applications:admin,access,get,put,post,delete:*:/**");
grant(info, principal, "users:access:*");
grant(info,
principal,
getPermissionFromPath(MANAGEMENT_APPLICATION_ID,
"access"));
grant(info,
principal,
getPermissionFromPath(MANAGEMENT_APPLICATION_ID,
"get,put,post,delete", "/**"));
} else {
// For regular service users, we find what organizations
// they're associated with
// An service user can be associated with multiple
// organizations
grant(info,
principal,
getPermissionFromPath(MANAGEMENT_APPLICATION_ID,
"access"));
// admin users cannot access the management app directly
// so open all permissions
grant(info,
principal,
getPermissionFromPath(MANAGEMENT_APPLICATION_ID,
"get,put,post,delete", "/**"));
role(info, principal, ROLE_ADMIN_USER);
try {
Map userOrganizations = management
.getOrganizationsForAdminUser(user.getUuid());
if (userOrganizations != null) {
for (UUID id : userOrganizations.keySet()) {
grant(info, principal,
"organizations:admin,access,get,put,post,delete:"
+ id);
}
organizationSet.putAll(userOrganizations);
Map userApplications = management
.getApplicationsForOrganizations(userOrganizations
.keySet());
if ((userApplications != null)
&& !userApplications.isEmpty()) {
grant(info,
principal,
"applications:admin,access,get,put,post,delete:"
+ StringUtils.join(
userApplications
.keySet(), ','));
applicationSet.putAll(userApplications);
}
role(info, principal, ROLE_ORGANIZATION_ADMIN);
role(info, principal, ROLE_APPLICATION_ADMIN);
}
} catch (Exception e) {
logger.error(
"Unable to construct admin user permissions", e);
}
}
} else if (principal instanceof ApplicationUserPrincipal) {
role(info, principal, ROLE_APPLICATION_USER);
UUID applicationId = ((ApplicationUserPrincipal) principal)
.getApplicationId();
AccessTokenCredentials tokenCredentials = ((ApplicationUserPrincipal) principal)
.getAccessTokenCredentials();
TokenInfo token = null;
if (tokenCredentials != null) {
try {
token = tokens
.getTokenInfo(tokenCredentials.getToken());
} catch (Exception e) {
logger.error("Unable to retrieve token info", e);
}
logger.debug("Token: {}", token);
}
grant(info, principal,
getPermissionFromPath(applicationId, "access"));
/*
* grant(info, principal, getPermissionFromPath(applicationId,
* "get,put,post,delete", "/users/${user}",
* "/users/${user}/feed", "/users/${user}/activities",
* "/users/${user}/groups", "/users/${user}/following/*",
* "/users/${user}/following/user/*"));
*/
EntityManager em = emf.getEntityManager(applicationId);
try {
String appName = (String) em.getProperty(
em.getApplicationRef(), "name");
applicationSet.put(applicationId, appName);
application = new ApplicationInfo(applicationId, appName);
} catch (Exception e) {
}
try {
Set permissions = em.getRolePermissions("default");
grant(info, principal, applicationId, permissions);
} catch (Exception e) {
logger.error("Unable to get user default role permissions",
e);
}
UserInfo user = ((ApplicationUserPrincipal) principal)
.getUser();
try {
Set permissions = em.getUserPermissions(user
.getUuid());
grant(info, principal, applicationId, permissions);
} catch (Exception e) {
logger.error("Unable to get user permissions", e);
}
try {
Set rolenames = em.getUserRoles(user.getUuid());
grantAppRoles(info, em, applicationId, token, principal, rolenames);
} catch (Exception e) {
logger.error("Unable to get user role permissions", e);
}
try {
//TODO TN. This is woefully inefficient, but temporary. Introduce cassandra backed shiro caching so this only ever happens once.
//See USERGRID-779 for details
Results r = em.getCollection(new SimpleEntityRef(
User.ENTITY_TYPE, user.getUuid()), "groups", null,
1000, Level.IDS, false);
if (r != null) {
Set rolenames = new HashSet();
for (UUID groupId : r.getIds()) {
Results roleResults = em.getCollection(new SimpleEntityRef(
Role.ENTITY_TYPE, groupId), "roles", null,
1000, Level.CORE_PROPERTIES, false);
for(Entity entity : roleResults.getEntities()){
rolenames.add(entity.getName());
}
}
grantAppRoles(info, em, applicationId, token, principal, rolenames);
}
} catch (Exception e) {
logger.error("Unable to get user group role permissions", e);
}
} else if (principal instanceof ApplicationGuestPrincipal) {
role(info, principal, ROLE_APPLICATION_USER);
UUID applicationId = ((ApplicationGuestPrincipal) principal)
.getApplicationId();
EntityManager em = emf.getEntityManager(applicationId);
try {
String appName = (String) em.getProperty(
em.getApplicationRef(), "name");
applicationSet.put(applicationId, appName);
application = new ApplicationInfo(applicationId, appName);
} catch (Exception e) {
}
grant(info, principal,
getPermissionFromPath(applicationId, "access"));
try {
Set permissions = em.getRolePermissions("guest");
grant(info, principal, applicationId, permissions);
} catch (Exception e) {
logger.error("Unable to get user default role permissions",
e);
}
}
}
// Store additional information in the request session to speed up
// looking up organization info
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
session.setAttribute("applications", applicationSet);
session.setAttribute("organizations", organizationSet);
if (organization != null) {
session.setAttribute("organization", organization);
}
if (application != null) {
session.setAttribute("application", application);
}
return info;
}
/**
* Grant all permissions for the role names on this application
* @param info
* @param em
* @param applicationId
* @param token
* @param principal
* @param rolenames
* @throws Exception
*/
private void grantAppRoles( SimpleAuthorizationInfo info, EntityManager em, UUID applicationId, TokenInfo token, PrincipalIdentifier principal, Set rolenames) throws Exception{
Map app_roles = em
.getRolesWithTitles(rolenames);
for (String rolename : rolenames) {
if ((app_roles != null) && (token != null)) {
Role role = app_roles.get(rolename);
if ((role != null)
&& (role.getInactivity() > 0)
&& (token.getInactive() > role
.getInactivity())) {
continue;
}
}
Set permissions = em
.getRolePermissions(rolename);
grant(info, principal, applicationId, permissions);
role(info,
principal,
"application-role:"
.concat(applicationId.toString())
.concat(":").concat(rolename));
}
}
public static void grant(SimpleAuthorizationInfo info,
PrincipalIdentifier principal, String permission) {
logger.debug("Principal {} granted permission: {}",
principal, permission);
info.addStringPermission(permission);
}
public static void role(SimpleAuthorizationInfo info,
PrincipalIdentifier principal, String role) {
logger.debug("Principal {} added to role: {}", principal, role);
info.addRole(role);
}
private static void grant(SimpleAuthorizationInfo info,
PrincipalIdentifier principal, UUID applicationId,
Set permissions) {
if (permissions != null) {
for (String permission : permissions) {
if (isNotBlank(permission)) {
String operations = "*";
if (permission.indexOf(':') != -1) {
operations = stringOrSubstringBeforeFirst(permission,
':');
}
if (isBlank(operations)) {
operations = "*";
}
permission = stringOrSubstringAfterFirst(permission, ':');
permission = "applications:" + operations + ":"
+ applicationId + ":" + permission;
grant(info, principal, permission);
}
}
}
}
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof PrincipalCredentialsToken;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy