Skip to content

Instantly share code, notes, and snippets.

@davidmc24
Forked from liling/gist:7052246
Created January 24, 2014 16:17
Show Gist options
  • Save davidmc24/8600531 to your computer and use it in GitHub Desktop.
Save davidmc24/8600531 to your computer and use it in GitHub Desktop.
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