-
-
Save davidmc24/8600531 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import base.shiro.ShiroRole | |
import base.shiro.ShiroUser | |
import org.apache.shiro.cas.CasAuthenticationException | |
import org.apache.shiro.authc.AccountException | |
import org.apache.shiro.authc.SimpleAuthenticationInfo | |
import org.apache.shiro.util.StringUtils | |
import org.apache.shiro.util.CollectionUtils | |
import org.apache.shiro.subject.PrincipalCollection | |
import org.apache.shiro.subject.SimplePrincipalCollection | |
import org.jasig.cas.client.authentication.AttributePrincipal | |
import org.jasig.cas.client.validation.* | |
/** | |
* Simple realm that authenticates users against an CAS server. | |
*/ | |
class ShiroCasRealm { | |
static authTokenClass = org.apache.shiro.cas.CasToken | |
private def ticketValidator = null | |
def grailsApplication | |
def shiroPermissionResolver | |
def grailsEvents | |
def authenticate(authToken) { | |
log.info "Attempting to authenticate ${authToken.userId} in CAS realm..." | |
def appConfig = grailsApplication.config | |
def serverUrl = appConfig.security.shiro.cas.serverUrl | |
if (!serverUrl) { | |
log.error(" the security.shiro.cas.serverUrl can not be empty.it should be https://host:port/cas") | |
} | |
def serviceUrl = appConfig.security.shiro.cas.serviceUrl | |
if (!serviceUrl) { | |
log.error(" the security.shiro.cas.serviceUrl can not be empty.it should be http://host:port/mycontextpath/shiro-cas") | |
} | |
if (authToken == null) { | |
throw new AccountException('cas tokens are not be null in this realm.') | |
} | |
String ticket = (String)authToken.getCredentials() | |
if (!StringUtils.hasText(ticket)) { | |
throw new AccountException('wrong cas token ticket:'+ticket) | |
} | |
if (ticketValidator==null) { | |
ticketValidator = new Cas20ServiceTicketValidator(serverUrl) | |
} | |
try { | |
// contact CAS server to validate service ticket | |
Assertion casAssertion = ticketValidator.validate(ticket, serviceUrl) | |
// get principal, user id and attributes | |
AttributePrincipal casPrincipal = casAssertion.principal | |
String userId = casPrincipal.name | |
if (log.debugEnabled) { | |
log.debug("Validate ticket : ${ticket} in CAS server : ${serverUrl} to retrieve user : ${userId}") | |
} | |
def pluginConfig = grailsApplication.getConfig().plugin.baseShiro | |
// Automatically create user account and grant default role | |
if (pluginConfig.cas.autoCreateUser) { | |
def user = ShiroUser.findByUsername(userId) | |
if (user == null) { | |
ShiroUser.withTransaction { | |
user = new ShiroUser() | |
user.username = userId | |
user.fullname = userId | |
user.save() | |
String defaultRole = pluginConfig.cas.defaultUserRole | |
if (defaultRole) { | |
ShiroRole role = ShiroRole.findByName(defaultRole) | |
if (role) { | |
user.addToRoles(role) | |
} | |
} | |
} | |
} | |
} | |
grailsEvents.event('security', 'afterUserLogin', userId) | |
Map<String, Object> attributes = casPrincipal.attributes | |
// refresh authentication token (user id + remember me) | |
authToken.setUserId(userId) | |
String rememberMeStringValue = (String)attributes.get('longTermAuthenticationRequestTokenUsed') | |
boolean isRemembered = rememberMeStringValue?.toBoolean() | |
if (isRemembered) { | |
authToken.setRememberMe(true) | |
} | |
// create simple authentication info | |
List<Object> principals = CollectionUtils.asList(userId, attributes) | |
PrincipalCollection principalCollection = new SimplePrincipalCollection(principals, this.toString()) | |
return new SimpleAuthenticationInfo(principalCollection, ticket) | |
} catch (TicketValidationException e) { | |
throw new CasAuthenticationException("Unable to validate ticket [" + ticket + "]", e); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
def hasRole(principal, roleName) { | |
def roles = ShiroUser.withCriteria { | |
roles { | |
eq("name", roleName) | |
} | |
eq("username", principal) | |
} | |
return roles.size() > 0 | |
} | |
def hasAllRoles(principal, roles) { | |
def r = ShiroUser.withCriteria { | |
roles { | |
'in'("name", roles) | |
} | |
eq("username", principal) | |
} | |
return r.size() == roles.size() | |
} | |
def isPermitted(principal, requiredPermission) { | |
// Does the user have the given permission directly associated | |
// with himself? | |
// | |
// First find all the permissions that the user has that match | |
// the required permission's type and project code. | |
def user = ShiroUser.findByUsername(principal, [cache: true]) | |
if (user == null) return false | |
def permissions = user.permissions | |
// Try each of the permissions found and see whether any of | |
// them confer the required permission. | |
def retval = permissions?.find { permString -> | |
// Create a real permission instance from the database | |
// permission. | |
def perm = shiroPermissionResolver.resolvePermission(permString) | |
// Now check whether this permission implies the required | |
// one. | |
if (perm.implies(requiredPermission)) { | |
// User has the permission! | |
return true | |
} | |
else { | |
return false | |
} | |
} | |
if (retval != null) { | |
// Found a matching permission! | |
return true | |
} | |
// If not, does he gain it through a role? | |
// | |
// Get the permissions from the roles that the user does have. | |
def results = ShiroUser.executeQuery("select distinct p from ShiroUser as user join user.roles as role join role.permissions as p where user.username = ?", [principal], [cache: true]) | |
// There may be some duplicate entries in the results, but | |
// at this stage it is not worth trying to remove them. Now, | |
// create a real permission from each result and check it | |
// against the required one. | |
retval = results.find { permString -> | |
// Create a real permission instance from the database | |
// permission. | |
def perm = shiroPermissionResolver.resolvePermission(permString) | |
// Now check whether this permission implies the required | |
// one. | |
if (perm.implies(requiredPermission)) { | |
// User has the permission! | |
return true | |
} | |
else { | |
return false | |
} | |
} | |
if (retval != null) { | |
// Found a matching permission! | |
return true | |
} | |
else { | |
return false | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment