- fixed few issues and cleaned up
This commit is contained in:
parent
ea156fe61e
commit
333dd13d6b
@ -17,13 +17,6 @@
|
||||
*
|
||||
* $Id: $
|
||||
*/
|
||||
import org.jsecurity.crypto.hash.Sha1Hash
|
||||
import org.bigbluebutton.web.domain.Role
|
||||
import org.bigbluebutton.web.domain.User
|
||||
import org.bigbluebutton.web.domain.UserRoleRel
|
||||
import org.bigbluebutton.web.domain.ScheduledSession
|
||||
import org.bigbluebutton.web.domain.Conference
|
||||
import java.util.UUID
|
||||
|
||||
class BootStrap {
|
||||
def jmsContainer
|
||||
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* BigBlueButton - http://www.bigbluebutton.org
|
||||
*
|
||||
* Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
|
||||
*
|
||||
* BigBlueButton is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $Id: $
|
||||
*/
|
||||
class SecurityFilters {
|
||||
def filters = {
|
||||
// Ensure that all controllers and actions require an authenticated user,
|
||||
// except for the "public" controller
|
||||
auth(controller: "*", action: "*") {
|
||||
before = {
|
||||
// Exclude the "join" controller.
|
||||
//if ((controllerName == "join") || (controllerName == "presentation")) return true
|
||||
|
||||
switch (controllerName) {
|
||||
case 'api':
|
||||
case 'presentation':
|
||||
return true
|
||||
break
|
||||
}
|
||||
// This just means that the user must be authenticated. He does
|
||||
// not need any particular role or permission.
|
||||
accessControl { true }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
/*
|
||||
* BigBlueButton - http://www.bigbluebutton.org
|
||||
*
|
||||
* Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
|
||||
*
|
||||
* BigBlueButton is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $Id: $
|
||||
*/
|
||||
import org.jsecurity.authc.AccountException
|
||||
import org.jsecurity.authc.IncorrectCredentialsException
|
||||
import org.jsecurity.authc.UnknownAccountException
|
||||
import org.jsecurity.authc.SimpleAccount
|
||||
import org.bigbluebutton.web.domain.User
|
||||
import org.bigbluebutton.web.domain.UserRoleRel
|
||||
import org.bigbluebutton.web.domain.UserPermissionRel
|
||||
import org.bigbluebutton.web.domain.Role
|
||||
import org.bigbluebutton.web.domain.RolePermissionRel
|
||||
import org.bigbluebutton.web.domain.Permission
|
||||
|
||||
class DbRealm {
|
||||
static authTokenClass = org.jsecurity.authc.UsernamePasswordToken
|
||||
|
||||
def credentialMatcher
|
||||
|
||||
def authenticate(authToken) {
|
||||
log.info "Attempting to authenticate ${authToken.username} in DB realm..."
|
||||
def username = authToken.username
|
||||
|
||||
// Null username is invalid
|
||||
if (username == null) {
|
||||
throw new AccountException('Null usernames are not allowed by this realm.')
|
||||
}
|
||||
|
||||
// Get the user with the given username. If the user is not
|
||||
// found, then they don't have an account and we throw an
|
||||
// exception.
|
||||
def user = User.findByUsername(username)
|
||||
if (!user) {
|
||||
throw new UnknownAccountException("No account found for user [${username}]")
|
||||
}
|
||||
|
||||
log.info "Found user '${user.username}' in DB"
|
||||
|
||||
// Now check the user's password against the hashed value stored
|
||||
// in the database.
|
||||
def account = new SimpleAccount(username, user.passwordHash, "DbRealm")
|
||||
if (!credentialMatcher.doCredentialsMatch(authToken, account)) {
|
||||
log.info 'Invalid password (DB realm)'
|
||||
throw new IncorrectCredentialsException("Invalid password for user '${username}'")
|
||||
}
|
||||
|
||||
return account
|
||||
}
|
||||
|
||||
def hasRole(principal, roleName) {
|
||||
def criteria = UserRoleRel.createCriteria()
|
||||
def roles = criteria.list {
|
||||
role {
|
||||
eq('name', roleName)
|
||||
}
|
||||
user {
|
||||
eq('username', principal)
|
||||
}
|
||||
}
|
||||
|
||||
return roles.size() > 0
|
||||
}
|
||||
|
||||
def hasAllRoles(principal, roles) {
|
||||
def criteria = UserRoleRel.createCriteria()
|
||||
def r = criteria.list {
|
||||
role {
|
||||
'in'('name', roles)
|
||||
}
|
||||
user {
|
||||
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 criteria = UserPermissionRel.createCriteria()
|
||||
def permissions = criteria.list {
|
||||
user {
|
||||
eq('username', principal)
|
||||
}
|
||||
permission {
|
||||
eq('type', requiredPermission.class.name)
|
||||
}
|
||||
}
|
||||
|
||||
// Try each of the permissions found and see whether any of
|
||||
// them confer the required permission.
|
||||
def retval = permissions?.find { rel ->
|
||||
// Create a real permission instance from the database
|
||||
// permission.
|
||||
def perm = null
|
||||
def constructor = findConstructor(rel.permission.type)
|
||||
if (constructor.parameterTypes.size() == 2) {
|
||||
perm = constructor.newInstance(rel.target, rel.actions)
|
||||
}
|
||||
else if (constructor.parameterTypes.size() == 1) {
|
||||
perm = constructor.newInstance(rel.target)
|
||||
}
|
||||
else {
|
||||
log.error "Unusable permission: ${rel.permission.type}"
|
||||
return false
|
||||
}
|
||||
|
||||
// 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?
|
||||
//
|
||||
// First, find the roles that the user has.
|
||||
def user = User.findByUsername(principal)
|
||||
def roles = UserRoleRel.findAllByUser(user)
|
||||
|
||||
// If the user has no roles, then he obviously has no permissions
|
||||
// via roles.
|
||||
if (roles.isEmpty()) return false
|
||||
|
||||
// Get the permissions from the roles that the user does have.
|
||||
criteria = RolePermissionRel.createCriteria()
|
||||
def results = criteria.list {
|
||||
'in'('role', roles.collect { it.role })
|
||||
permission {
|
||||
eq('type', requiredPermission.class.name)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 { rel ->
|
||||
def perm = null
|
||||
def constructor = findConstructor(rel.permission.type)
|
||||
if (constructor.parameterTypes.size() == 2) {
|
||||
perm = constructor.newInstance(rel.target, rel.actions)
|
||||
}
|
||||
else if (constructor.parameterTypes.size() == 1) {
|
||||
perm = constructor.newInstance(rel.target)
|
||||
}
|
||||
else {
|
||||
log.error "Unusable permission: ${rel.permission.type}"
|
||||
return false
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
def findConstructor(className) {
|
||||
// Load the required permission class.
|
||||
def clazz = this.class.classLoader.loadClass(className)
|
||||
|
||||
// Check the available constructors. If any take two
|
||||
// string parameters, we use that one and pass in the
|
||||
// target and actions string. Otherwise we try a single
|
||||
// parameter constructor and pass in just the target.
|
||||
def preferredConstructor = null
|
||||
def fallbackConstructor = null
|
||||
clazz.declaredConstructors.each { constructor ->
|
||||
def numParams = constructor.parameterTypes.size()
|
||||
if (numParams == 2) {
|
||||
if (constructor.parameterTypes[0].equals(String) &&
|
||||
constructor.parameterTypes[1].equals(String)) {
|
||||
preferredConstructor = constructor
|
||||
}
|
||||
}
|
||||
else if (numParams == 1) {
|
||||
if (constructor.parameterTypes[0].equals(String)) {
|
||||
fallbackConstructor = constructor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (preferredConstructor != null ? preferredConstructor : fallbackConstructor)
|
||||
}
|
||||
}
|
31
bigbluebutton-web/grails-app/services/org/bigbluebutton/pbx/asterisk/AsteriskAgiService.groovy
Normal file → Executable file
31
bigbluebutton-web/grails-app/services/org/bigbluebutton/pbx/asterisk/AsteriskAgiService.groovy
Normal file → Executable file
@ -26,7 +26,6 @@ import org.asteriskjava.fastagi.AgiRequest
|
||||
import org.asteriskjava.fastagi.AgiScript
|
||||
|
||||
import java.util.Calendar
|
||||
import org.bigbluebutton.web.domain.ScheduledSession
|
||||
import org.bigbluebutton.web.services.DynamicConferenceService
|
||||
|
||||
|
||||
@ -38,36 +37,6 @@ public class AsteriskAgiService implements AgiScript {
|
||||
public void service(AgiRequest request, AgiChannel channel)
|
||||
throws AgiException {
|
||||
|
||||
def number = request.getParameter("conference")
|
||||
log.debug "Looking for conference $number"
|
||||
def conf = ScheduledSession.findByVoiceConferenceBridge(number)
|
||||
|
||||
if (conf) {
|
||||
log.debug("found conference " + conf.name)
|
||||
def startTime = conf.startDateTime.time - _10_minutes
|
||||
def endTime = conf.endDateTime.time + _10_minutes
|
||||
def now = new Date()
|
||||
|
||||
log.debug("startTime " + new Date(startTime) + " endTime " + new Date(endTime) + " now " + now)
|
||||
|
||||
if ((startTime < now.time) && (endTime > now.time)) {
|
||||
log.debug("Setting channel var CONFERENCE_FOUND to $number")
|
||||
channel.setVariable("CONFERENCE_FOUND", number)
|
||||
} else {
|
||||
log.debug("The conference $number has no schedule at this moment")
|
||||
setConferenceNotFound()
|
||||
}
|
||||
} else {
|
||||
log.debug "Cannot find conference from database. Looking in Dynamic conference"
|
||||
if (dynamicConferenceService == null) log.error "dynamicConferenceService is NULL"
|
||||
if (dynamicConferenceService.isMeetingWithVoiceBridgeExist(number)) {
|
||||
log.debug("Setting channel var CONFERENCE_FOUND to $number")
|
||||
channel.setVariable("CONFERENCE_FOUND", number)
|
||||
} else {
|
||||
log.debug("Could not find conference $number")
|
||||
setConferenceNotFound()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setConferenceNotFound() {
|
||||
|
@ -1,553 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 Peter Ledbrook.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import org.codehaus.groovy.grails.commons.ControllerArtefactHandler
|
||||
import org.codehaus.groovy.grails.commons.GrailsClassUtils
|
||||
import org.codehaus.groovy.grails.plugins.support.GrailsPluginUtils
|
||||
import org.codehaus.groovy.grails.plugins.web.filters.FilterConfig
|
||||
|
||||
import org.jsecurity.SecurityUtils
|
||||
import org.jsecurity.authc.credential.Sha1CredentialsMatcher
|
||||
import org.jsecurity.grails.*
|
||||
import org.jsecurity.realm.Realm
|
||||
import org.jsecurity.subject.DelegatingSubject
|
||||
import org.jsecurity.web.DefaultWebSecurityManager
|
||||
|
||||
import org.springframework.beans.factory.config.MethodInvokingFactoryBean
|
||||
|
||||
class JsecurityGrailsPlugin {
|
||||
def version = '0.3'
|
||||
def author = 'Peter Ledbrook'
|
||||
def authorEmail = 'peter@cacoethes.co.uk'
|
||||
def title = 'Security support via the JSecurity framework.'
|
||||
def description = '''\
|
||||
Adds a security layer to your Grails application, allowing you to
|
||||
protect pages based on a user's roles and/or permissions.
|
||||
'''
|
||||
def documentation = 'http://grails.codehaus.org/JSecurity+Plugin'
|
||||
|
||||
def grailsVersion = GrailsPluginUtils.grailsVersion
|
||||
def loadAfter = [ 'controllers', 'services' ]
|
||||
def observe = [ 'controllers' ]
|
||||
def watchedResources = 'file:./grails-app/realms/**/*Realm.groovy'
|
||||
def artefacts = [ RealmArtefactHandler ]
|
||||
|
||||
def roleMaps = [:]
|
||||
def permMaps = [:]
|
||||
|
||||
def doWithSpring = {
|
||||
// Configure the realms defined in the project.
|
||||
def realmBeans = []
|
||||
def realmClasses = application.realmClasses
|
||||
application.realmClasses.each { realmClass ->
|
||||
log.info "Registering realm: ${realmClass.fullName}"
|
||||
configureRealm.delegate = delegate
|
||||
|
||||
realmBeans << configureRealm(realmClass)
|
||||
}
|
||||
|
||||
// This currently does not work in certain cases because of
|
||||
// a bug in Grails.
|
||||
// 'org.jsecurity.spring.LifecycleBeanPostProcessor'(org.jsecurity.spring.LifecycleBeanPostProcessor)
|
||||
|
||||
|
||||
// The default credential matcher.
|
||||
credentialMatcher(Sha1CredentialsMatcher) {
|
||||
storedCredentialsHexEncoded = true
|
||||
}
|
||||
|
||||
jsecSecurityManager(DefaultWebSecurityManager) { bean ->
|
||||
bean.destroyMethod = "destroy"
|
||||
|
||||
realms = realmBeans.collect { ref(it) }
|
||||
|
||||
// Allow the user to customise the session type: either
|
||||
// 'http' or 'jsecurity'.
|
||||
if (application.config.jsecurity.session.mode) {
|
||||
sessionMode = application.config.jsecurity.session.mode
|
||||
}
|
||||
|
||||
// Allow the user to customise the authentication strategy.
|
||||
if (application.config.jsecurity.authentication.strategy) {
|
||||
modularAuthenticationStrategy = application.config.jsecurity.authentication.strategy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def doWithApplicationContext = { applicationContext ->
|
||||
// Add any extra realms that might have been defined in the
|
||||
// project. To do that, we first just get all the beans that
|
||||
// implement the Realm interface.
|
||||
def beans = applicationContext.getBeanNamesForType(Realm) as List
|
||||
|
||||
// Now filter out the beans created by the plugin for the
|
||||
// realm artefacts.
|
||||
beans = beans.findAll { !(it.endsWith("Wrapper") || it.endsWith("Proxy")) }
|
||||
|
||||
// Finally add the remaining beans to the security manager.
|
||||
log.info "Registering native realms: $beans"
|
||||
def mgr = applicationContext.getBean('jsecSecurityManager')
|
||||
mgr.realms.addAll(beans.collect { applicationContext.getBean(it) })
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds 'roleMap' and 'permissionMap' properties to controllers
|
||||
* so that our before-interceptor can query them to find out
|
||||
* whether a user has the required role/permission for an action.
|
||||
*/
|
||||
def doWithDynamicMethods = { ctx ->
|
||||
// Get the access control information from the controllers, if
|
||||
// there are any.
|
||||
if (manager?.hasGrailsPlugin("controllers")) {
|
||||
// Process each controller.
|
||||
application.controllerClasses.each { controllerClass ->
|
||||
processController(controllerClass, log)
|
||||
}
|
||||
}
|
||||
|
||||
application.filtersClasses.each { filterClass ->
|
||||
filterClass.clazz.metaClass.getRoleMap = { String controller -> return roleMaps[controller] }
|
||||
filterClass.clazz.metaClass.getPermissionMap = { String controller -> return permMaps[controller] }
|
||||
}
|
||||
|
||||
// Get the config option that determines whether authentication
|
||||
// is required for access control or not. By default, it is
|
||||
// required.
|
||||
boolean authcRequired = true
|
||||
if (application.config.jsecurity.authc.required instanceof Boolean) {
|
||||
authcRequired = application.config.jsecurity.authc.required
|
||||
}
|
||||
|
||||
// Add an 'accessControl' method to FilterConfig (so that it's
|
||||
// available from Grails filters).
|
||||
def mc = FilterConfig.metaClass
|
||||
|
||||
mc.accessControl << { -> return accessControlMethod(delegate, authcRequired) }
|
||||
mc.accessControl << { Map args -> return accessControlMethod(delegate, authcRequired, args) }
|
||||
mc.accessControl << { Closure c -> return accessControlMethod(delegate, authcRequired, [:], c) }
|
||||
mc.accessControl << { Map args, Closure c -> return accessControlMethod(delegate, authcRequired, args, c) }
|
||||
}
|
||||
|
||||
def doWithWebDescriptor = { webXml ->
|
||||
def contextParam = webXml.'context-param'
|
||||
contextParam[contextParam.size() - 1] + {
|
||||
'filter' {
|
||||
'filter-name'('securityContextFilter')
|
||||
'filter-class'('org.jsecurity.spring.SpringJSecurityFilter')
|
||||
'init-param' {
|
||||
'param-name'('securityManagerBeanName')
|
||||
'param-value'('jsecSecurityManager')
|
||||
}
|
||||
|
||||
// If a JSecurity configuration is available, add it
|
||||
// as an 'init-param' of the filter. This config should
|
||||
// be in .ini format. See the JSecurity documentation
|
||||
// for more information.
|
||||
if (application.config.jsecurity.filter.config) {
|
||||
'init-param' {
|
||||
'param-name'('config')
|
||||
'param-value'(application.config.jsecurity.filter.config)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Place the JSecurity filter after the Spring character encoding
|
||||
// filter, otherwise the latter filter won't work.
|
||||
def filter = webXml.'filter-mapping'.find { it.'filter-name'.text() == "charEncodingFilter" }
|
||||
|
||||
// NOTE: The following shenanigans are designed to ensure that
|
||||
// the filter mapping is inserted in the right location under
|
||||
// a variety of circumstances. However, at this point in time
|
||||
// it's a bit of wasted effort because Grails itself can't handle
|
||||
// certain situations, such as no filter mappings at all, or
|
||||
// a SiteMesh one but no character encoding filter mapping.
|
||||
// Bleh.
|
||||
|
||||
if (!filter) {
|
||||
// Of course, if there is no char encoding filter, the next
|
||||
// requirement is that we come before the SiteMesh filter.
|
||||
// This is trickier to accomplish. First we find out at what
|
||||
// index the SiteMesh filter mapping is.
|
||||
int i = 0
|
||||
int siteMeshIndex = -1
|
||||
webXml.'filter-mapping'.each {
|
||||
if (it.'filter-name'.text().equalsIgnoreCase("sitemesh")) {
|
||||
siteMeshIndex = i
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
if (siteMeshIndex > 0) {
|
||||
// There is at least one other filter mapping that comes
|
||||
// before the SiteMesh one, so we can simply use the filter
|
||||
// mapping that comes immediately before SiteMesh as the
|
||||
// insertion point.
|
||||
filter = webXml.'filter-mapping'[siteMeshIndex - 1]
|
||||
}
|
||||
else if (siteMeshIndex == 0 || webXml.'filter-mapping'.size() == 0) {
|
||||
// If the index of the SiteMesh filter mapping is 0, i.e.
|
||||
// it's the first one, we need to use the last filter
|
||||
// definition as the insertion point. We also need to do
|
||||
// this if there are no filter mappings.
|
||||
def filters = webXml.'filter'
|
||||
filter = filters[filters.size() - 1]
|
||||
}
|
||||
else {
|
||||
// Simply add this filter mapping to the end.
|
||||
def filterMappings = webXml.'filter-mapping'
|
||||
filter = filterMappings[filterMappings.size() - 1]
|
||||
}
|
||||
}
|
||||
|
||||
// Finally add the JSecurity filter mapping after the selected
|
||||
// insertion point.
|
||||
filter + {
|
||||
'filter-mapping' {
|
||||
'filter-name'('securityContextFilter')
|
||||
'url-pattern'("/*")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def onChange = { event ->
|
||||
if (application.isControllerClass(event.source)) {
|
||||
// Get the GrailsClass instance for the controller.
|
||||
def controllerClass = application.getControllerClass(event.source?.name)
|
||||
|
||||
// If no GrailsClass can be found, i.e. 'controllerClass'
|
||||
// is null, then this is a new controller.
|
||||
if (controllerClass == null) {
|
||||
controllerClass = application.addArtefact(ControllerArtefactHandler.TYPE, event.source)
|
||||
}
|
||||
|
||||
// Now update the role and permission information for this
|
||||
// controller.
|
||||
log.info "Reconfiguring access control for ${controllerClass.shortName}"
|
||||
processController(controllerClass, log)
|
||||
return
|
||||
}
|
||||
else if (application.isRealmClass(event.source)) {
|
||||
log.info "Realm modified!"
|
||||
|
||||
def context = event.ctx
|
||||
if (!context) {
|
||||
log.debug("Application context not found - can't reload.")
|
||||
return
|
||||
}
|
||||
|
||||
boolean isNew = event.application.getRealmClass(event.source?.name) == null
|
||||
def realmClass = application.addArtefact(RealmArtefactHandler.TYPE, event.source)
|
||||
|
||||
if (isNew) {
|
||||
try {
|
||||
def beanDefinitions = beans(configureRealm.curry(realmClass))
|
||||
beanDefinitions.registerBeans(context)
|
||||
}
|
||||
catch (MissingMethodException ex) {
|
||||
// This version of Grails does not support this.
|
||||
log.warn("Unable to register beans (Grails version < 0.5.5)")
|
||||
}
|
||||
}
|
||||
else {
|
||||
def realmName = realmClass.shortName
|
||||
def wrapperName = "${realmName}Wrapper".toString()
|
||||
|
||||
def beans = beans {
|
||||
"${realmName}Class"(MethodInvokingFactoryBean) {
|
||||
targetObject = ref('grailsApplication', true)
|
||||
targetMethod = 'getArtefact'
|
||||
arguments = [RealmArtefactHandler.TYPE, realmClass.fullName]
|
||||
}
|
||||
|
||||
"${realmName}Instance"(ref("${realmName}Class")) {bean ->
|
||||
bean.factoryMethod = 'newInstance'
|
||||
bean.singleton = true
|
||||
bean.autowire = 'byName'
|
||||
}
|
||||
|
||||
"${wrapperName}"(RealmWrapper) {
|
||||
realm = ref("${realmName}Instance")
|
||||
tokenClass = GrailsClassUtils.getStaticPropertyValue(realmClass.clazz, 'authTokenClass')
|
||||
}
|
||||
}
|
||||
|
||||
if (context) {
|
||||
context.registerBeanDefinition("${realmName}Class", beans.getBeanDefinition("${realmName}Class"))
|
||||
context.registerBeanDefinition("${realmName}Instance", beans.getBeanDefinition("${realmName}Instance"))
|
||||
context.registerBeanDefinition(wrapperName, beans.getBeanDefinition(wrapperName))
|
||||
}
|
||||
|
||||
// HACK
|
||||
//
|
||||
// The problem here is that the subject has been created
|
||||
// within a servlet filter *before* the realm reloading
|
||||
// has occurred. The above 'registerBeanDefinition()'
|
||||
// calls result in the security manager being destroyed
|
||||
// and a new one created, but the subject still refers
|
||||
// to the old security manager.
|
||||
//
|
||||
// So, we update the subject's security manager directly.
|
||||
// Note that we are using Groovy's ability to circumvent
|
||||
// visibility controls since the 'securityManager' field
|
||||
// is protected, not public.
|
||||
if (SecurityUtils.subject instanceof DelegatingSubject) {
|
||||
SecurityUtils.subject.@securityManager = context.getBean("jsecSecurityManager")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def onApplicationChange = { event ->
|
||||
// TODO Implement code that is executed when any class in a GrailsApplication changes
|
||||
// the event contain: event.source, event.application and event.applicationContext objects
|
||||
}
|
||||
|
||||
def configureRealm = { grailsClass ->
|
||||
def realmName = grailsClass.shortName
|
||||
|
||||
// Create the realm bean.
|
||||
"${realmName}Class"(MethodInvokingFactoryBean) {
|
||||
targetObject = ref('grailsApplication', true)
|
||||
targetMethod = 'getArtefact'
|
||||
arguments = [RealmArtefactHandler.TYPE, grailsClass.fullName]
|
||||
}
|
||||
|
||||
"${realmName}Instance"(ref("${realmName}Class")) {bean ->
|
||||
bean.factoryMethod = 'newInstance'
|
||||
bean.singleton = true
|
||||
bean.autowire = 'byName'
|
||||
}
|
||||
|
||||
// Wrap each realm with an adapter that implements the
|
||||
// JSecurity Realm interface.
|
||||
def wrapperName = "${realmName}Wrapper".toString()
|
||||
"${wrapperName}"(RealmWrapper) {
|
||||
realm = ref("${realmName}Instance")
|
||||
tokenClass = GrailsClassUtils.getStaticPropertyValue(grailsClass.clazz, 'authTokenClass')
|
||||
}
|
||||
|
||||
// Return the bean name for this realm.
|
||||
return wrapperName
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of the "accessControl()" dynamic method available
|
||||
* to filters. It requires a reference to the filter so that it can
|
||||
* access the dynamic properties and methods, such as "request" and
|
||||
* "redirect()".
|
||||
* @param filter The filter instance that the "accessControl()"
|
||||
* method is called from.
|
||||
* @param authcRequired Specifies whether the default behaviour is
|
||||
* to only allow access if the user is authenticated. If
|
||||
* <code>false</code>, remembered users are also allowed unless this
|
||||
* setting is overridden in the arguments of the method.
|
||||
* @param args An argument map as passed to the "accessControl()"
|
||||
* method. Only the "auth" argument is supported at the moment.
|
||||
* @param c The closure to execute if the user has not been blocked
|
||||
* by the authentication requirement. The closure should return
|
||||
* <code>true</code> to allow access, or <code>false</code> otherwise.
|
||||
*/
|
||||
boolean accessControlMethod(filter, boolean authcRequired, Map args = [:], Closure c = null) {
|
||||
// If we're accessing the auth controller itself, we don't
|
||||
// want to check whether the user is authenticated, otherwise
|
||||
// we end up in an infinite loop of redirects.
|
||||
if (filter.controllerName == 'auth') return true
|
||||
|
||||
// Get hold of the filters class instance.
|
||||
def filtersClass = filter.filtersDefinition
|
||||
|
||||
// ...and the HTTP request.
|
||||
def request = filter.request
|
||||
|
||||
// Is an authenticated user required for this URL? If not,
|
||||
// then we can do a permission check for remembered users
|
||||
// as well as authenticated ones. Otherwise, remembered
|
||||
// users will have to log in.
|
||||
def authenticatedUserRequired = args["auth"] || (args["auth"] == null && authcRequired)
|
||||
|
||||
// If required, check that the user is authenticated.
|
||||
def subject = SecurityUtils.subject
|
||||
if (subject.principal == null || (authenticatedUserRequired && !subject.authenticated)) {
|
||||
// User is not authenticated, so deal with it.
|
||||
if (filtersClass.metaClass.respondsTo(filtersClass, 'onNotAuthenticated')) {
|
||||
filtersClass.onNotAuthenticated(subject, filter)
|
||||
}
|
||||
else {
|
||||
// Default behaviour is to redirect to the login
|
||||
// page.
|
||||
def targetUri = request.forwardURI - request.contextPath
|
||||
def query = request.queryString
|
||||
if (query) {
|
||||
if (!query.startsWith('?')) {
|
||||
query = '?' + query
|
||||
}
|
||||
targetUri += query
|
||||
}
|
||||
|
||||
filter.redirect(
|
||||
controller: 'auth',
|
||||
action: 'login',
|
||||
params: [ targetUri: targetUri ])
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
def isPermitted
|
||||
if (c == null) {
|
||||
// Check that the user has the required permission for
|
||||
// the target controller/action. This is access control
|
||||
// by convention.
|
||||
isPermitted = subject.isPermitted(new JsecBasicPermission(filter.controllerName, filter.actionName ?: 'index'))
|
||||
}
|
||||
else {
|
||||
// Call the closure with the access control builder and
|
||||
// check the result. The closure will return 'true' if the
|
||||
// user is permitted access, otherwise 'false'.
|
||||
c.delegate = new FilterAccessControlBuilder(subject)
|
||||
isPermitted = c.call()
|
||||
}
|
||||
|
||||
if (!isPermitted) {
|
||||
// User does not have the required permission(s)
|
||||
if (filtersClass.metaClass.respondsTo(filtersClass, 'onUnauthorized')) {
|
||||
filtersClass.onUnauthorized(subject, filter)
|
||||
}
|
||||
else {
|
||||
// Default behaviour is to redirect to the
|
||||
// 'unauthorized' page.
|
||||
filter.redirect(controller: 'auth', action: 'unauthorized')
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
def processController(controllerClass, log) {
|
||||
// This is the wrapped class.
|
||||
def clazz = controllerClass.clazz
|
||||
|
||||
// These maps are made available to controllers via the
|
||||
// dynamically injected 'roleMap' and 'permissionMap'
|
||||
// properties.
|
||||
def roleMap = [:]
|
||||
def permissionMap = [:]
|
||||
this.roleMaps[controllerClass.logicalPropertyName] = roleMap
|
||||
this.permMaps[controllerClass.logicalPropertyName] = permissionMap
|
||||
|
||||
// Process any annotations that this controller declares.
|
||||
try {
|
||||
// Check whether the JVM supports annotations.
|
||||
Class.forName('java.lang.annotation.Annotation')
|
||||
|
||||
// Process any annotations on this controller.
|
||||
log.debug "Processing annotations on ${controllerClass.shortName}"
|
||||
processAnnotations(controllerClass, roleMap, permissionMap, log)
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
}
|
||||
|
||||
// Check whether this controller class has a static
|
||||
// 'accessControl' property. If so, use that as a definition
|
||||
// of the controller's role and permission requirements.
|
||||
// Note that these settings override any annotations that
|
||||
// are declared in the class.
|
||||
if (GrailsClassUtils.isStaticProperty(clazz, 'accessControl')) {
|
||||
// The property should be a Closure. If it's not, we
|
||||
// can't do anything with it.
|
||||
def c = GrailsClassUtils.getStaticPropertyValue(clazz, 'accessControl')
|
||||
if (!(c instanceof Closure)) {
|
||||
log.error("Static property [accessControl] on controller [${controllerClass.fullName}] is not a closure.")
|
||||
return
|
||||
}
|
||||
|
||||
// Process the closure, building a map of actions to
|
||||
// permissions and a map of actions to roles.
|
||||
def b = new AccessControlBuilder(clazz)
|
||||
c.delegate = b
|
||||
c.call()
|
||||
|
||||
roleMap.putAll(b.roleMap)
|
||||
permissionMap.putAll(b.permissionMap)
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Access control role map for controller '${controllerClass.logicalPropertyName}': ${roleMap}")
|
||||
log.debug("Access control permission map for controller '${controllerClass.logicalPropertyName}': ${permissionMap}")
|
||||
}
|
||||
}
|
||||
|
||||
// Inject the role and permission maps into the controller.
|
||||
controllerClass.metaClass.getRoleMap = {->
|
||||
return roleMap
|
||||
}
|
||||
|
||||
controllerClass.metaClass.getPermissionMap = {->
|
||||
return permissionMap
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process any plugin annotations (RoleRequired or PermissionRequired)
|
||||
* on the given controller. Any annotations are evaluated and used
|
||||
* to update the role and permission maps.
|
||||
*/
|
||||
def processAnnotations(controllerClass, roleMap, permissionMap, log) {
|
||||
def clazz = controllerClass.clazz
|
||||
clazz.declaredFields.each { field ->
|
||||
// First see whether this field/action requires any roles.
|
||||
// We load the annotation classes dynamically so that the
|
||||
// plugin can be used with the 1.4 JDK.
|
||||
def ann = field.getAnnotation(Class.forName('org.jsecurity.grails.annotation.RoleRequired'))
|
||||
if (ann != null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Annotation role required by controller '${controllerClass.logicalPropertyName}', action '${field.name}': ${ann.value()}")
|
||||
}
|
||||
|
||||
// Found RoleRequired annotation. Configure the
|
||||
// interceptor for this.
|
||||
def roles = roleMap[field.name]
|
||||
if (!roles) {
|
||||
roles = []
|
||||
roleMap[field.name] = roles
|
||||
}
|
||||
roles << ann.value()
|
||||
}
|
||||
|
||||
// Now check for permission requirements.
|
||||
ann = field.getAnnotation(Class.forName('org.jsecurity.grails.annotation.PermissionRequired'))
|
||||
if (ann != null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Annotation permission required by controller '${controllerClass.logicalPropertyName}', action '${field.name}': ${ann.value()}")
|
||||
}
|
||||
|
||||
// Found PermissionRequired annotation. Configure
|
||||
// the interceptor for this.
|
||||
def permissions = permissionMap[field.name]
|
||||
if (!permissions) {
|
||||
permissions = []
|
||||
permissionMap[field.name] = permissions
|
||||
}
|
||||
|
||||
def constructor = ann.type().getConstructor([ String, String ] as Class[])
|
||||
permissions << constructor.newInstance([ ann.target(), ann.actions() ] as Object[])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
#Do not edit app.grails.* properties, they may change automatically. DO NOT put application configuration in here, it is not the right place!
|
||||
#Thu Mar 27 15:48:39 GMT 2008
|
||||
app.grails.version=1.0.3
|
||||
app.name=grails-jsecurity
|
@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 Peter Ledbrook.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
import org.jsecurity.SecurityUtils
|
||||
|
||||
/**
|
||||
* <p>A Grails filter that implements the same functionality as the old
|
||||
* JsecAuthBase abstract controller. It uses the role and permission
|
||||
* maps injected into the filter to determine whether the current user
|
||||
* has the required rights for a particular request.</p>
|
||||
* <p>The role and permission maps are populated via the 'accessControl'
|
||||
* property on controllers.</p>
|
||||
*/
|
||||
class JsecurityFilters {
|
||||
def filters = {
|
||||
accessControlCheck(controller: '*', action: '*') {
|
||||
before = {
|
||||
if (grailsApplication.config.jsecurity.legacy.filter.enabled) {
|
||||
// Check that the current user is authenticated and
|
||||
// has permission to access the current action.
|
||||
def subject = SecurityUtils.subject
|
||||
|
||||
// Get the role and permission maps for this controller.
|
||||
def roleMap = getRoleMap(controllerName)
|
||||
def permissionMap = getPermissionMap(controllerName)
|
||||
|
||||
// Is this action configured for access control?
|
||||
if (!roleMap.containsKey(actionName) && !permissionMap.containsKey(actionName) &&
|
||||
!roleMap.containsKey('*') && !permissionMap.containsKey('*')) {
|
||||
// This action has no access control requirements,
|
||||
// so the user does not need to be logged in to
|
||||
// access it.
|
||||
return true
|
||||
}
|
||||
|
||||
// Is the user authenticated?
|
||||
if (!subject.authenticated) {
|
||||
// User is not authenticated, so redirect to the login page.
|
||||
redirect(
|
||||
controller: 'auth',
|
||||
action: 'login',
|
||||
params: [ targetUri: request.forwardURI - request.contextPath ])
|
||||
return false
|
||||
}
|
||||
|
||||
// First check any required roles.
|
||||
def requiredRoles = roleMap[actionName]
|
||||
if (requiredRoles == null) requiredRoles = []
|
||||
if (roleMap['*']) {
|
||||
// Add any roles that apply to all actions. Note
|
||||
// that a new list is created from merging the
|
||||
// existing required roles with those for all
|
||||
// actions ('*'). We shouldn't modify the data in
|
||||
// the role map itself.
|
||||
requiredRoles += roleMap['*']
|
||||
}
|
||||
|
||||
if (!requiredRoles.isEmpty() && !subject.hasAllRoles(requiredRoles)) {
|
||||
// User does not have the required roles. Redirect
|
||||
// to an error page?
|
||||
redirect(controller: 'auth', action: 'unauthorized')
|
||||
return false
|
||||
}
|
||||
|
||||
// Now check any required permissions.
|
||||
def requiredPermissions = permissionMap[actionName]
|
||||
if (requiredPermissions == null) requiredPermissions = []
|
||||
if (permissionMap['*']) {
|
||||
// Add any permission that applies to all actions.
|
||||
requiredPermissions += permissionMap['*']
|
||||
}
|
||||
|
||||
if (!requiredPermissions.isEmpty() && !subject.isPermittedAll(requiredPermissions)) {
|
||||
// User does not have the requisite permissions -
|
||||
// redirect to an error page?
|
||||
redirect(controller: 'auth', action: 'unauthorized')
|
||||
return false
|
||||
}
|
||||
|
||||
// User has passed all checks, so they may access the
|
||||
// action.
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
import org.jsecurity.SecurityUtils
|
||||
|
||||
/**
|
||||
* Base class for controllers to provide access control. Controllers
|
||||
* no longer need the extend this class as the access control is now
|
||||
* handled by Grails filters.
|
||||
* @deprecated
|
||||
*/
|
||||
abstract class JsecAuthBase {
|
||||
def beforeInterceptor = {
|
||||
// Check that the current user is authenticated and
|
||||
// has permission to access the current action.
|
||||
def subject = SecurityUtils.subject
|
||||
|
||||
// Is this action configured for access control?
|
||||
if (!roleMap.containsKey(actionName) && !permissionMap.containsKey(actionName) &&
|
||||
!roleMap.containsKey('*') && !permissionMap.containsKey('*')) {
|
||||
// This action has no access control requirements,
|
||||
// so the user does not need to be logged in to
|
||||
// access it.
|
||||
return true
|
||||
}
|
||||
|
||||
// Is the user authenticated?
|
||||
if (!subject.authenticated) {
|
||||
// Save the original URI that the user is attempting to
|
||||
// access.
|
||||
session.originalRequestParams = params
|
||||
|
||||
// User is not authenticated, so redirect to the login page.
|
||||
redirect(controller: 'auth', action: 'login')
|
||||
return false
|
||||
}
|
||||
|
||||
// First check any required roles.
|
||||
def requiredRoles = roleMap[actionName]
|
||||
if (requiredRoles == null) requiredRoles = []
|
||||
if (roleMap['*']) {
|
||||
// Add any roles that apply to all actions.
|
||||
requiredRoles.addAll(roleMap['*'])
|
||||
}
|
||||
|
||||
if (!requiredRoles.isEmpty() && !subject.hasAllRoles(requiredRoles)) {
|
||||
// User does not have the required roles. Redirect
|
||||
// to an error page?
|
||||
redirect(controller: 'auth', action: 'unauthorized')
|
||||
return false
|
||||
}
|
||||
|
||||
// Now check any required permissions.
|
||||
def requiredPermissions = permissionMap[actionName]
|
||||
if (requiredPermissions == null) requiredPermissions = []
|
||||
if (permissionMap['*']) {
|
||||
// Add any permission that applies to all actions.
|
||||
requiredPermissions.addAll(permissionMap['*'])
|
||||
}
|
||||
|
||||
if (!requiredPermissions.isEmpty() && !subject.isPermittedAll(requiredPermissions)) {
|
||||
// User does not have the requisite permissions -
|
||||
// redirect to an error page?
|
||||
redirect(controller: 'auth', action: 'unauthorized')
|
||||
return false
|
||||
}
|
||||
|
||||
// User has passed all checks, so they may access the
|
||||
// action.
|
||||
return true
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
login.failed = Invalid username and/or password
|
@ -1,312 +0,0 @@
|
||||
import org.jsecurity.SecurityUtils
|
||||
|
||||
class JsecTagLib {
|
||||
static namespace = 'jsec'
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* is logged in.
|
||||
*/
|
||||
def isLoggedIn = { attrs, body ->
|
||||
if (checkAuthenticated()) {
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* is not logged in.
|
||||
*/
|
||||
def isNotLoggedIn = { attrs, body ->
|
||||
if (!checkAuthenticated()) {
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A synonym for 'isLoggedIn'. This is the same name as used by
|
||||
* the standard JSecurity tag library.
|
||||
*/
|
||||
def authenticated = isLoggedIn
|
||||
|
||||
/**
|
||||
* A synonym for 'isNotLoggedIn'. This is the same name as used by
|
||||
* the standard JSecurity tag library.
|
||||
*/
|
||||
def notAuthenticated = isNotLoggedIn
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* is either logged in or remembered from a previous session (via
|
||||
* the "remember me" cookie).
|
||||
*/
|
||||
def user = { attrs, body ->
|
||||
if (SecurityUtils.subject.principal != null) {
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* is neither logged in nor remembered from a previous session (via
|
||||
* the "remember me" cookie).
|
||||
*/
|
||||
def notUser = { attrs, body ->
|
||||
if (SecurityUtils.subject.principal == null) {
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* is remembered from a previous session (via the "remember me"
|
||||
* cookie) but not currently logged in.
|
||||
*/
|
||||
def remembered = { attrs, body ->
|
||||
if (SecurityUtils.subject.principal != null && !checkAuthenticated()) {
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* is not remembered from a previous session (via the "remember me"
|
||||
* cookie). This is the case if they are a guest user or logged in.
|
||||
*/
|
||||
def notRemembered = { attrs, body ->
|
||||
if (SecurityUtils.subject.principal == null || checkAuthenticated()) {
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Outputs the string form of the current user's identity. By default
|
||||
* this assumes that the subject has only one principal; its string
|
||||
* representation is written to the page.</p>
|
||||
* Optional attributes:
|
||||
* <ul>
|
||||
* <li><i>type</i>: Species the type or class of the principal to
|
||||
* use</li>
|
||||
* <li><i>property</i>: Specifies the name of the property on the
|
||||
* principal to use as the string representation, e.g.
|
||||
* <code>firstName</code></li>
|
||||
* </ul>
|
||||
*/
|
||||
def principal = { attrs ->
|
||||
def subject = SecurityUtils.subject
|
||||
|
||||
if (subject != null) {
|
||||
// Get the principal to print out.
|
||||
def principal
|
||||
if (attrs['type']) {
|
||||
// A principal of a particular type/class has been
|
||||
// requested.
|
||||
principal = subject.getPrincipalByType(attrs['type'])
|
||||
}
|
||||
else {
|
||||
principal = subject.principal
|
||||
}
|
||||
|
||||
// Now write the principal to the page.
|
||||
if (principal != null) {
|
||||
// If a 'property' attribute has been specified, then
|
||||
// we access the property with the same name on the
|
||||
// principal and write that to the page. Otherwise, we
|
||||
// just use the string representation of the principal
|
||||
// itself.
|
||||
if (attrs['property']) {
|
||||
out << principal."${attrs['property']}"
|
||||
}
|
||||
else {
|
||||
out << principal.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* has the given role.
|
||||
*/
|
||||
def hasRole = { attrs, body ->
|
||||
// Does the user have the required role?
|
||||
if (checkRole(attrs)) {
|
||||
// Output the body text.
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* does not have the given role.
|
||||
*/
|
||||
def lacksRole = { attrs, body ->
|
||||
// Does the user have the required role?
|
||||
if (!checkRole(attrs)) {
|
||||
// Output the body text.
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* has all the given roles (inversion of lacksAnyRole).
|
||||
*/
|
||||
def hasAllRoles = { attrs, body ->
|
||||
// Extract the name of the role from the attributes.
|
||||
def inList = attrs['in']
|
||||
if (!inList)
|
||||
throwTagError('Tag [hasAllRoles] must have [in] attribute.')
|
||||
if (SecurityUtils.subject.hasAllRoles(inList)) {
|
||||
// Output the body text.
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* has none of the given roles (inversion of hasAllRoles).
|
||||
*/
|
||||
def lacksAnyRole = { attrs, body ->
|
||||
// Extract the name of the role from the attributes.
|
||||
def inList = attrs['in']
|
||||
if (!inList)
|
||||
throwTagError('Tag [lacksAnyRole] must have [in] attribute.')
|
||||
if (!SecurityUtils.subject.hasAllRoles(inList)) {
|
||||
// Output the body text.
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* has any of the given roles (inversion of lacksAllRoles).
|
||||
*/
|
||||
def hasAnyRole = { attrs, body ->
|
||||
// Extract the name of the role from the attributes.
|
||||
def inList = attrs['in']
|
||||
if (!inList)
|
||||
throwTagError('Tag [hasAnyRole] must have [in] attribute.')
|
||||
if (SecurityUtils.subject.hasRoles(inList).any()) {
|
||||
// Output the body text.
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* doesn't have all of the given roles (inversion of hasAnyRole).
|
||||
*/
|
||||
def lacksAllRoles = { attrs, body ->
|
||||
// Extract the name of the role from the attributes.
|
||||
def inList = attrs['in']
|
||||
if (!inList)
|
||||
throwTagError('Tag [lacksAllRoles] must have [in] attribute.')
|
||||
if (!SecurityUtils.subject.hasRoles(inList).any()) {
|
||||
// Output the body text.
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* has the given permission.
|
||||
*/
|
||||
def hasPermission = { attrs, body ->
|
||||
if (checkPermission(attrs)) {
|
||||
// Output the body text.
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tag only writes its body to the output if the current user
|
||||
* does not have the given permission.
|
||||
*/
|
||||
def lacksPermission = { attrs, body ->
|
||||
if (!checkPermission(attrs)) {
|
||||
// Output the body text.
|
||||
out << body()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current user is authenticated or not. Returns
|
||||
* <code>true</code> if the user is authenticated, otherwise
|
||||
* <code>false</code>.
|
||||
*/
|
||||
private boolean checkAuthenticated() {
|
||||
// Get the user's security context.
|
||||
return SecurityUtils.subject.authenticated
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current user has the role specified in the
|
||||
* given tag attributes. Returns <code>true</code> if the user
|
||||
* has the role, otherwise <code>false</code>.
|
||||
*/
|
||||
private boolean checkRole(attrs) {
|
||||
// Extract the name of the role from the attributes.
|
||||
def roleName = attrs['name']
|
||||
def inList = attrs['in']
|
||||
if (roleName) {
|
||||
// Does the user have the required role?
|
||||
return SecurityUtils.subject.hasRole(roleName)
|
||||
}
|
||||
else if (inList) {
|
||||
log.warn ('Use of tags [hasRole/lacksRole] with attribute [in] is deprecated. Use tags [hasAnyRole/lacksAllRoles] instead.')
|
||||
boolean[] results = SecurityUtils.subject.hasRoles(inList)
|
||||
return results.any()
|
||||
}
|
||||
else {
|
||||
throwTagError('Tag [hasRole] must have one of [name] or [in] attributes.')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current user has the permission specified in
|
||||
* the given tag attributes. Returns <code>true</code> if the user
|
||||
* has the permission, otherwise <code>false</code>.
|
||||
*/
|
||||
private boolean checkPermission(attrs) {
|
||||
def permission
|
||||
def permClass = attrs['type']
|
||||
if (!permClass) {
|
||||
// If 'type' is not set, then the permission itself must
|
||||
// be specified.
|
||||
permission = attrs['permission']
|
||||
|
||||
if (!permission) {
|
||||
throwTagError('Tag [hasPermission] must have either a [type] attribute or a [permission] one.')
|
||||
}
|
||||
|
||||
if (!(permission instanceof org.jsecurity.authz.Permission)) {
|
||||
throwTagError('Attribute [permission] must be an instance of org.jsecurity.authz.Permission.')
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If 'type' is given, then 'actions' must also be set.
|
||||
// 'target' defaults to '*'.
|
||||
def actions = attrs['actions']
|
||||
if (!actions) {
|
||||
throwTagError('Tag [hasPermission] must have an [actions] attribute if [type] is used.')
|
||||
}
|
||||
|
||||
def target = attrs['target']
|
||||
if (!target) target = '*'
|
||||
|
||||
// Create the permission from the information given.
|
||||
try {
|
||||
def clazz = Class.forName(permClass)
|
||||
def constructor = clazz.getConstructor([ String, String ] as Class[])
|
||||
permission = constructor.newInstance([ target, actions ] as Object[])
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throwTagError("Cannot find class [${permClass}] from attribute [hasPermission].")
|
||||
}
|
||||
}
|
||||
|
||||
// Now we have the permission, check whether the user has it.
|
||||
return SecurityUtils.subject.isPermitted(permission)
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,14 +0,0 @@
|
||||
<plugin name='jsecurity' version='0.3'>
|
||||
<author>Peter Ledbrook</author>
|
||||
<authorEmail>peter@cacoethes.co.uk</authorEmail>
|
||||
<title>Security support via the JSecurity framework.</title>
|
||||
<description>Adds a security layer to your Grails application, allowing you to
|
||||
protect pages based on a user's roles and/or permissions.
|
||||
</description>
|
||||
<documentation>http://grails.codehaus.org/JSecurity+Plugin</documentation>
|
||||
<resources>
|
||||
<resource>JsecurityFilters</resource>
|
||||
<resource>JsecTagLib</resource>
|
||||
<resource>JsecAuthBase</resource>
|
||||
</resources>
|
||||
</plugin>
|
@ -1,28 +0,0 @@
|
||||
import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU
|
||||
|
||||
grailsHome = Ant.project.properties."environment.GRAILS_HOME"
|
||||
|
||||
includeTargets << new File ("${grailsHome}/scripts/Init.groovy")
|
||||
includeTargets << new File ("${jsecurityPluginDir}/scripts/_JsecInternal.groovy")
|
||||
|
||||
target("default": "The description of the script goes here!") {
|
||||
// Make sure any arguments have been parsed if the parser is
|
||||
// available.
|
||||
def hasArgsParser = getBinding().variables.containsKey('argsMap')
|
||||
if (hasArgsParser) {
|
||||
depends(parseArguments, checkVersion)
|
||||
}
|
||||
else {
|
||||
depends(checkVersion)
|
||||
}
|
||||
|
||||
createAuthController()
|
||||
}
|
||||
|
||||
target(createAuthController: "The implementation task") {
|
||||
// Copy over the standard auth controller.
|
||||
installTemplate("AuthController.groovy", "grails-app/controllers", "controllers")
|
||||
|
||||
// Now copy over the views for the controller.
|
||||
installTemplate("login.gsp", "grails-app/views/auth", "views/auth")
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU
|
||||
|
||||
Ant.property(environment: 'env')
|
||||
grailsHome = Ant.antProject.properties.'env.GRAILS_HOME'
|
||||
|
||||
includeTargets << new File ("${grailsHome}/scripts/Init.groovy")
|
||||
includeTargets << new File ("${jsecurityPluginDir}/scripts/_JsecInternal.groovy")
|
||||
|
||||
target ('default': 'Creates a database JSecurity realm') {
|
||||
// Make sure any arguments have been parsed if the parser is
|
||||
// available.
|
||||
hasArgsParser = getBinding().variables.containsKey('argsMap')
|
||||
if (hasArgsParser) {
|
||||
depends(parseArguments, checkVersion)
|
||||
}
|
||||
else {
|
||||
depends(checkVersion)
|
||||
}
|
||||
|
||||
createDbRealm()
|
||||
}
|
||||
|
||||
target('createDbRealm': 'Creates a basic, but flexible database-backed realm.') {
|
||||
// Get the prefix for the realm name. Default is "Jsec" to avoid
|
||||
// name conflicts.
|
||||
def prefix = "Jsec"
|
||||
if (hasArgsParser && argsMap['prefix'] != null) {
|
||||
prefix = argsMap['prefix']
|
||||
}
|
||||
|
||||
// First create the domain objects: JsecUser, JsecRole, etc.
|
||||
def domainClasses = [
|
||||
'User',
|
||||
'Role',
|
||||
'Permission',
|
||||
'RolePermissionRel',
|
||||
'UserRoleRel',
|
||||
'UserPermissionRel' ]
|
||||
|
||||
def artefactPath = "grails-app/domain"
|
||||
Ant.mkdir(dir:"${basedir}/${artefactPath}")
|
||||
|
||||
domainClasses.each { domainClass ->
|
||||
installTemplateEx("${prefix}${domainClass}.groovy", artefactPath, "domain", "Jsec${domainClass}.groovy") {
|
||||
Ant.replace(file: artefactFile) {
|
||||
Ant.replacefilter(token: '@domain.prefix@', value: prefix)
|
||||
}
|
||||
}
|
||||
event("CreatedArtefact", ['', domainClass])
|
||||
}
|
||||
|
||||
// Copy over the standard DB realm.
|
||||
def className = "${prefix}DbRealm"
|
||||
installTemplateEx("${className}.groovy", "grails-app/realms", "", "JsecDbRealm.groovy") {
|
||||
Ant.replace(file: artefactFile) {
|
||||
Ant.replacefilter(token: '@realm.name@', value: className)
|
||||
Ant.replacefilter(token: '@domain.prefix@', value: prefix)
|
||||
}
|
||||
}
|
||||
|
||||
event("CreatedArtefact", ['Realm', className])
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
Ant.property(environment: 'env')
|
||||
grailsHome = Ant.antProject.properties.'env.GRAILS_HOME'
|
||||
|
||||
includeTargets << new File ("${grailsHome}/scripts/Init.groovy")
|
||||
|
||||
target ('default': 'Creates a database JSecurity realm') {
|
||||
// Make sure any arguments have been parsed if the parser is
|
||||
// available.
|
||||
def hasArgsParser = getBinding().variables.containsKey('argsMap')
|
||||
if (hasArgsParser) {
|
||||
depends(parseArguments, checkVersion)
|
||||
}
|
||||
else {
|
||||
depends(checkVersion)
|
||||
}
|
||||
|
||||
// Get the prefix for the realm name. Default is "Jsec" to avoid
|
||||
// name conflicts.
|
||||
def prefix = "Jsec"
|
||||
if (hasArgsParser && argsMap['prefix'] != null) {
|
||||
prefix = argsMap['prefix']
|
||||
}
|
||||
|
||||
// Copy over the standard LDAP realm.
|
||||
def className = "${prefix}LdapRealm".toString()
|
||||
def artefactPath = 'grails-app/realms'
|
||||
def artefactFile = "${basedir}/${artefactPath}/${className}.groovy"
|
||||
if (new File(artefactFile).exists()) {
|
||||
Ant.input(
|
||||
addProperty: "${args}.${className}.overwrite",
|
||||
message: "${className} already exists. Overwrite? [y/n]")
|
||||
|
||||
if (Ant.antProject.properties."${args}.${className}.overwrite" == "n") {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the template file to the 'grails-app/realms' directory.
|
||||
templateFile = "${jsecurityPluginDir}/src/templates/artifacts/JsecLdapRealm.groovy"
|
||||
if (!new File(templateFile).exists()) {
|
||||
Ant.echo("[JSecurity plugin] Error: src/templates/artifacts/JsecLdapRealm.groovy does not exist!")
|
||||
return
|
||||
}
|
||||
|
||||
Ant.copy(file: templateFile, tofile: artefactFile, overwrite: true)
|
||||
Ant.replace(file: artefactFile) {
|
||||
Ant.replacefilter(token: '@realm.name@', value: className)
|
||||
}
|
||||
|
||||
event("CreatedFile", [artefactFile])
|
||||
event("CreatedArtefact", ['Realm', className])
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
includeTargets << new File ("${jsecurityPluginDir}/scripts/CreateDbRealm.groovy")
|
||||
includeTargets << new File ("${jsecurityPluginDir}/scripts/CreateAuthController.groovy")
|
||||
|
||||
target("default": "Sets up a basic security system with a database realm, auth controller, etc.") {
|
||||
// Make sure any arguments have been parsed if the parser is
|
||||
// available.
|
||||
hasArgsParser = getBinding().variables.containsKey('argsMap')
|
||||
if (hasArgsParser) {
|
||||
depends(parseArguments, checkVersion)
|
||||
}
|
||||
else {
|
||||
depends(checkVersion)
|
||||
}
|
||||
|
||||
createDbRealm()
|
||||
createAuthController()
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Script invoked when the plugin is installed.
|
||||
* @author Peter Ledbrook
|
||||
*/
|
||||
Ant.mkdir(dir:"${basedir}/grails-app/realms")
|
||||
|
||||
// Install the message bundle.
|
||||
Ant.copy(
|
||||
file: "${jsecurityPluginDir}/grails-app/i18n/messages.properties",
|
||||
tofile: "grails-app/i18n/jsecurity.properties")
|
@ -1,59 +0,0 @@
|
||||
/**
|
||||
* Installs a JSecurity template into the current project, where the
|
||||
* new file has the same name as the template.
|
||||
* @param artefactName The name of the file to create, i.e. the name
|
||||
* of the template.
|
||||
* @param artefactPath The location relative to the project root to
|
||||
* store the new file.
|
||||
* @param templatePath The location relative to the plugin's
|
||||
* "src/templates" directory where the template file can be found.
|
||||
*/
|
||||
installTemplate = { String artefactName, String artefactPath, String templatePath ->
|
||||
installTemplateEx(artefactName, artefactPath, templatePath, artefactName, null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a JSecurity template into the current project, with optional
|
||||
* post-processing.
|
||||
* @param artefactName The name of the file to create.
|
||||
* @param artefactPath The location relative to the project root to
|
||||
* store the new file.
|
||||
* @param templatePath The location relative to the plugin's
|
||||
* "src/templates" directory where the template file can be found.
|
||||
* @param templateName The filename of the template.
|
||||
* @param c An optional closure that will be invoked once the template
|
||||
* has been installed. The closure has the property "artefactFile"
|
||||
* available to it, which is the file path (as a File) of the newly
|
||||
* created file. This parameter may be <code>null</code>, in which
|
||||
* no post-processing is performed.
|
||||
*/
|
||||
installTemplateEx = { String artefactName, String artefactPath, String templatePath, String templateName, Closure c ->
|
||||
// Copy over the standard auth controller.
|
||||
def artefactFile = "${basedir}/${artefactPath}/${artefactName}"
|
||||
if (new File(artefactFile).exists()) {
|
||||
Ant.input(
|
||||
addProperty: "${args}.${artefactName}.overwrite",
|
||||
message: "${artefactName} already exists. Overwrite? [y/n]")
|
||||
|
||||
if (Ant.antProject.properties."${args}.${artefactName}.overwrite" == "n") {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the template file to the 'grails-app/controllers' directory.
|
||||
templateFile = "${jsecurityPluginDir}/src/templates/artifacts/${templatePath}/${templateName}"
|
||||
if (!new File(templateFile).exists()) {
|
||||
Ant.echo("[JSecurity plugin] Error: src/templates/artifacts/${templatePath}/${templateName} does not exist!")
|
||||
return
|
||||
}
|
||||
|
||||
Ant.copy(file: templateFile, tofile: artefactFile, overwrite: true)
|
||||
|
||||
// Perform any custom processing that may be required.
|
||||
if (c) {
|
||||
c.delegate = [ artefactFile: artefactFile ]
|
||||
c.call()
|
||||
}
|
||||
|
||||
event("CreatedFile", [artefactFile])
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Script invoked when the host project is upgraded.
|
||||
* @author Peter Ledbrook
|
||||
*/
|
||||
Ant.mkdir(dir:"${basedir}/grails-app/realms")
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 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 org.jsecurity.grails
|
||||
|
||||
/**
|
||||
* This is the builder that handles the access control DSL used in
|
||||
* controllers to specify role and permission settings.
|
||||
*/
|
||||
class AccessControlBuilder {
|
||||
private Class controllerClass
|
||||
private Map internalPermissionMap = [:]
|
||||
private Map internalRoleMap = [:]
|
||||
|
||||
AccessControlBuilder(Class controllerClass) {
|
||||
this.controllerClass = controllerClass
|
||||
}
|
||||
|
||||
/**
|
||||
* Read-only access to the 'permissionMap' property.
|
||||
*/
|
||||
def getPermissionMap() {
|
||||
return Collections.unmodifiableMap(this.internalPermissionMap)
|
||||
}
|
||||
|
||||
/**
|
||||
* Read-only access to the 'roleMap' property.
|
||||
*/
|
||||
def getRoleMap() {
|
||||
return Collections.unmodifiableMap(this.internalRoleMap)
|
||||
}
|
||||
|
||||
/**
|
||||
* Expects a map for an argument.
|
||||
*/
|
||||
def role(args) {
|
||||
// TODO Add support for a single argument (which is the role name).
|
||||
def roleName = args['name']
|
||||
if (!roleName) {
|
||||
throw new RuntimeException('The [name] parameter is required when defining a role.')
|
||||
}
|
||||
|
||||
if (args['action']) {
|
||||
// Single action requires this role.
|
||||
addRoleToAction(roleName, args['action'])
|
||||
}
|
||||
else if (args['only']) {
|
||||
// Several actions require this role.
|
||||
def actions = args['only']
|
||||
actions.each { action ->
|
||||
addRoleToAction(roleName, action)
|
||||
}
|
||||
}
|
||||
else {
|
||||
// All the actions require this role.
|
||||
addRoleToAction(roleName, '*')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expects a map for an argument.
|
||||
*/
|
||||
def permission(args) {
|
||||
def perm = args['perm']
|
||||
if (!perm) {
|
||||
throw new RuntimeException('The [perm] parameter is required when defining a permission.')
|
||||
}
|
||||
|
||||
if (args['action']) {
|
||||
// Single action requires this permission.
|
||||
addPermissionToAction(perm, args['action'])
|
||||
}
|
||||
else if (args['only']) {
|
||||
// Several actions require this perm.
|
||||
def actions = args['only']
|
||||
actions.each { action ->
|
||||
addPermissionToAction(perm, action)
|
||||
}
|
||||
}
|
||||
else {
|
||||
// All the actions require this perm.
|
||||
addPermissionToAction(perm, '*')
|
||||
}
|
||||
}
|
||||
|
||||
private addRoleToAction(role, action) {
|
||||
def roleList = internalRoleMap[action]
|
||||
if (!roleList) {
|
||||
internalRoleMap[action] = [ role ]
|
||||
}
|
||||
else {
|
||||
roleList << role
|
||||
}
|
||||
}
|
||||
|
||||
private addPermissionToAction(permission, action) {
|
||||
def permissionList = internalPermissionMap[action]
|
||||
if (!permissionList) {
|
||||
internalPermissionMap[action] = [ permission ]
|
||||
}
|
||||
else {
|
||||
permissionList << permission
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
package org.jsecurity.grails
|
||||
|
||||
import org.jsecurity.authz.Permission
|
||||
import org.jsecurity.subject.Subject
|
||||
|
||||
class FilterAccessControlBuilder {
|
||||
private Subject subject
|
||||
|
||||
FilterAccessControlBuilder(Subject subject) {
|
||||
this.subject = subject
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the user associated with the builder's security
|
||||
* context has the given role or not.
|
||||
*/
|
||||
boolean role(String roleName) {
|
||||
return this.subject.hasRole(roleName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the user associated with the builder's security
|
||||
* context has the given permission or not.
|
||||
*/
|
||||
boolean permission(Permission permission) {
|
||||
return this.subject.isPermitted(permission)
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks whether the user associated with the builder's security
|
||||
* context has permission for a given type and set of actions. The
|
||||
* map must have 'type' and 'actions' entries. The method should be
|
||||
* called like this:</p>
|
||||
* <pre>
|
||||
* permission(type: 'profile', actions: 'edit')
|
||||
* permission(type: 'book', actions: [ 'show', 'modify' ])
|
||||
* permission(type: 'book', actions: 'show, modify')
|
||||
* </pre>
|
||||
*/
|
||||
boolean permission(Map args) {
|
||||
// First check that the argument map has the required entries.
|
||||
if (!args['type']) {
|
||||
throw new IllegalArgumentException("The 'type' parameter must be provided to 'permission()'")
|
||||
}
|
||||
else if (!(args['type'] instanceof String)) {
|
||||
throw new IllegalArgumentException("The 'type' parameter must be a string.")
|
||||
}
|
||||
|
||||
if (!args['actions']) {
|
||||
throw new IllegalArgumentException("The 'actions' parameter must be provided to 'permission()'")
|
||||
}
|
||||
else if (!(args['actions'] instanceof String || args['actions'] instanceof Collection)) {
|
||||
throw new IllegalArgumentException("The 'actions' parameter must be a string or a collection of strings.")
|
||||
}
|
||||
|
||||
// Create a new permission from the given parameters.
|
||||
def p = new JsecBasicPermission(args['type'], args['actions'])
|
||||
|
||||
// Check whether the currently authenticated user has the
|
||||
// permission.
|
||||
return this.subject.isPermitted(p)
|
||||
}
|
||||
}
|
@ -1,286 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 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 org.jsecurity.grails
|
||||
|
||||
import org.apache.commons.logging.LogFactory
|
||||
import org.jsecurity.authc.AuthenticationException
|
||||
import org.jsecurity.authc.AuthenticationToken
|
||||
import org.jsecurity.authz.AuthorizationException
|
||||
import org.jsecurity.authz.Permission
|
||||
import org.jsecurity.authz.UnauthorizedException
|
||||
import org.jsecurity.subject.PrincipalCollection
|
||||
import org.jsecurity.authc.AuthenticationInfo
|
||||
import org.jsecurity.authc.SimpleAuthenticationInfo
|
||||
import org.jsecurity.subject.SimplePrincipalCollection
|
||||
|
||||
/**
|
||||
* Simple implementation of the JSecurity Realm that wraps a 'Realm'
|
||||
* artefact. It is basically an adapter between the Grails world and
|
||||
* the JSecurity world.
|
||||
* @author Peter Ledbrook
|
||||
*/
|
||||
class RealmWrapper extends RealmAdapter {
|
||||
private static final LOGGER = LogFactory.getLog('grails.app.realm')
|
||||
|
||||
Object realm
|
||||
Class tokenClass
|
||||
|
||||
void setRealm(Object realm) {
|
||||
this.realm = realm
|
||||
}
|
||||
|
||||
void setTokenClass(Class clazz) {
|
||||
this.tokenClass = clazz
|
||||
}
|
||||
|
||||
AuthenticationInfo getAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
|
||||
// If the target realm has an 'authenticate' method, we use
|
||||
// that.
|
||||
try {
|
||||
def account = this.realm.authenticate(authenticationToken)
|
||||
|
||||
if (account instanceof AuthenticationInfo) {
|
||||
return account
|
||||
}
|
||||
else {
|
||||
// Create an account to host the returned principals.
|
||||
def principals = []
|
||||
if (account instanceof Collection) {
|
||||
principals.addAll(account)
|
||||
}
|
||||
else {
|
||||
principals << account
|
||||
}
|
||||
|
||||
return new SimpleAuthenticationInfo(new SimplePrincipalCollection(account, getName()), null)
|
||||
}
|
||||
}
|
||||
catch (MissingMethodException ex) {
|
||||
// No authentication performed.
|
||||
if (ex.message.indexOf('authenticate') && LOGGER.errorEnabled) {
|
||||
LOGGER.error "Unable to authenticate with ${getName()}", ex
|
||||
}
|
||||
return null
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (LOGGER.infoEnabled) {
|
||||
LOGGER.info "Unable to authenticate with ${getName()} - ${ex.message}"
|
||||
}
|
||||
if (LOGGER.debugEnabled) {
|
||||
LOGGER.debug 'The exception', ex
|
||||
}
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jsecurity.realm.Realm#getName()
|
||||
*/
|
||||
String getName() {
|
||||
return this.realm.class.name
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jsecurity.realm.Realm#supports(java.lang.Class)
|
||||
*/
|
||||
boolean supports(AuthenticationToken authenticationToken) {
|
||||
if (this.tokenClass) {
|
||||
return this.tokenClass.isAssignableFrom(authenticationToken.getClass())
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jsecurity.authz.AuthorizationOperations#checkPermission(Object, org.jsecurity.authz.Permission)
|
||||
*/
|
||||
void checkPermission(PrincipalCollection principal, Permission permission) throws AuthorizationException {
|
||||
if (!isPermitted(principal, permission)) {
|
||||
throw new UnauthorizedException("User '${principal.name}' does not have permission '${permission}'")
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jsecurity.authz.AuthorizationOperations#checkPermissions(Object, java.util.Collection)
|
||||
*/
|
||||
void checkPermissions(PrincipalCollection principal, Collection<Permission> permissions) throws AuthorizationException {
|
||||
if (!isPermittedAll(principal, permissions)) {
|
||||
throw new UnauthorizedException("User '${principal.name}' does not have the required permissions.")
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jsecurity.authz.AuthorizationOperations#checkRole(Object, java.lang.String)
|
||||
*/
|
||||
void checkRole(PrincipalCollection principal, String role) throws AuthorizationException {
|
||||
if (!hasRole(principal, role)) {
|
||||
throw new UnauthorizedException("User '${principal.name}' does not have role '${role}'")
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jsecurity.authz.AuthorizationOperations#checkRoles(Object, java.util.Collection)
|
||||
*/
|
||||
void checkRoles(PrincipalCollection principal, Collection<String> roles) throws AuthorizationException {
|
||||
if (!hasAllRoles(principal, roles)) {
|
||||
throw new UnauthorizedException("User '${principal.name}' does not have all these roles: ${roles}")
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jsecurity.authz.AuthorizationOperations#hasAllRoles(Object, java.util.Collection)
|
||||
*/
|
||||
boolean hasAllRoles(PrincipalCollection principal, Collection<String> roles) {
|
||||
// First try the 'hasAllRoles' method on the realm.
|
||||
principal = getFirstPrincipal(principal)
|
||||
if (this.realm.metaClass.respondsTo(this.realm, "hasAllRoles")) {
|
||||
this.realm.hasAllRoles(principal, roles)
|
||||
}
|
||||
else if (this.realm.metaClass.respondsTo(this.realm, "hasRole")) {
|
||||
// No specific method, so just check each role individually
|
||||
// until we find one that the principal does not have, or
|
||||
// we reach the end of the collection of roles.
|
||||
roles.each { role ->
|
||||
// It the principal does not have this role, then
|
||||
// we can immediately return 'false'.
|
||||
if (!this.realm.hasRole(getFirstPrincipal(principal), role)) return false
|
||||
}
|
||||
|
||||
// All roles have checked out ok, so the principal has
|
||||
// all the given roles.
|
||||
return true
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jsecurity.authz.AuthorizationOperations#hasRole(Object, java.lang.String)
|
||||
*/
|
||||
boolean hasRole(PrincipalCollection principal, String role) {
|
||||
// Try the 'hasRole' method on the realm.
|
||||
if (this.realm.metaClass.respondsTo(this.realm, "hasRole")) {
|
||||
return this.realm.hasRole(getFirstPrincipal(principal), role)
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jsecurity.authz.AuthorizationOperations#hasRoles(Object, java.util.List)
|
||||
*/
|
||||
boolean[] hasRoles(PrincipalCollection principal, List<String> roles) {
|
||||
// First try the 'hasRoles' method on the realm.
|
||||
principal = getFirstPrincipal(principal)
|
||||
|
||||
if (this.realm.metaClass.respondsTo(this.realm, "hasRoles")) {
|
||||
return this.realm.hasRoles(principal, roles)
|
||||
}
|
||||
else if (this.realm.metaClass.respondsTo(this.realm, "hasRole")) {
|
||||
// No specific method, so check each role individually.
|
||||
boolean[] retval = new boolean[roles.size()]
|
||||
for (int i in 0..<roles.size()) {
|
||||
retval[i] = hasRole(principal, roles[i])
|
||||
}
|
||||
|
||||
return retval
|
||||
}
|
||||
else {
|
||||
// Can't check roles, so return 'false' for each role
|
||||
// requested.
|
||||
boolean[] retval = new boolean[roles.size()]
|
||||
for (int i in 0..<roles.size()) {
|
||||
retval[i] = false;
|
||||
}
|
||||
|
||||
return retval
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jsecurity.authz.AuthorizationOperations#isPermitted(Object, org.jsecurity.authz.Permission)
|
||||
*/
|
||||
boolean isPermitted(PrincipalCollection principal, Permission permission) {
|
||||
// Try the 'isPermitted' method on the realm.
|
||||
if (this.realm.metaClass.respondsTo(this.realm, "isPermitted")) {
|
||||
return this.realm.isPermitted(getFirstPrincipal(principal), permission)
|
||||
}
|
||||
else {
|
||||
// Can't check permissions, so simply return 'false'.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jsecurity.authz.AuthorizationOperations#isPermitted(Object, java.util.List)
|
||||
*/
|
||||
boolean[] isPermitted(PrincipalCollection principal, List<Permission> permissions) {
|
||||
boolean[] retval = new boolean[permissions.size()]
|
||||
|
||||
// Try the 'isPermitted' method on the realm.
|
||||
principal = getFirstPrincipal(principal)
|
||||
if (this.realm.metaClass.respondsTo(this.realm, "isPermitted")) {
|
||||
for (int i in 0..<retval.length) {
|
||||
retval[i] = this.realm.isPermitted(principal, permissions[i])
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Can't check permissions, so simply return 'false' for
|
||||
// all of them.
|
||||
for (int i in 0..<retval.length) {
|
||||
retval[i] = false
|
||||
}
|
||||
}
|
||||
|
||||
return retval
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jsecurity.authz.AuthorizationOperations#isPermittedAll(Object, java.util.Collection)
|
||||
*/
|
||||
boolean isPermittedAll(PrincipalCollection principal, Collection<Permission> permissions) {
|
||||
// Try the 'isPermittedAll' method on the realm.
|
||||
principal = getFirstPrincipal(principal)
|
||||
if (this.realm.metaClass.respondsTo(this.realm, "isPermittedAll")) {
|
||||
return this.realm.isPermittedAll(principal, permissions)
|
||||
}
|
||||
else if (this.realm.metaClass.respondsTo(this.realm, "isPermitted")) {
|
||||
// No specific method, so just check each permission
|
||||
// individually until we find one that the principal
|
||||
// does not have, or we reach the end of the collection
|
||||
// of roles.
|
||||
permissions.each { permission ->
|
||||
// It the principal does not have this permission,
|
||||
// then we can immediately return 'false'.
|
||||
if (!this.realm.isPermitted(principal, permission)) return false
|
||||
}
|
||||
|
||||
// All permissions have checked out ok, so the principal has
|
||||
// all the given permissions.
|
||||
return true
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private getFirstPrincipal(PrincipalCollection principal) {
|
||||
return principal.asList()[0]
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 Peter Ledbrook.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Peter Ledbrook.
|
||||
*
|
||||
* 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.jsecurity.grails;
|
||||
|
||||
import org.codehaus.groovy.grails.commons.AbstractInjectableGrailsClass;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class DefaultRealmGrailsClass extends AbstractInjectableGrailsClass implements RealmGrailsClass {
|
||||
public DefaultRealmGrailsClass(Class wrappedClass) {
|
||||
super(wrappedClass, RealmArtefactHandler.TYPE);
|
||||
}
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 Peter Ledbrook.
|
||||
*
|
||||
* 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.jsecurity.grails;
|
||||
|
||||
|
||||
import org.jsecurity.authz.Permission;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A basic permission class that can be used with the default DB realm
|
||||
* provided with the plugin.
|
||||
*/
|
||||
public class JsecBasicPermission implements Permission {
|
||||
public static final String WILDCARD = "*";
|
||||
|
||||
private String target;
|
||||
private Set actions;
|
||||
private String actionsString;
|
||||
|
||||
/**
|
||||
* Creates a new permission with the given actions. <b>Note</b> an
|
||||
* action may not have any whitespace in it, or ',' or ';' characters.
|
||||
* @param target The permission target. The meaning of 'target' is
|
||||
* application dependent, for example it may be a file path, a URL,
|
||||
* a controller name, or a component name.
|
||||
* @param actions A string of actions separated by ',', ';', or
|
||||
* whitespace. For example, 'view,edit', 'create, delete',
|
||||
* 'create; modify', 'view edit' are all valid two-action strings.
|
||||
*/
|
||||
public JsecBasicPermission(String target, String actions) {
|
||||
this.target = target;
|
||||
|
||||
// Convert the delimited string of actions into a set.
|
||||
this.actions = actionsStringToSet(actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new permission with the given actions.
|
||||
* @param target The permission target. The meaning of 'target' is
|
||||
* application dependent, for example it may be a file path, a URL,
|
||||
* a controller name, or a component name.
|
||||
* @param actions A collection of action strings, for example 'view'
|
||||
* 'edit', 'create', and 'delete'.
|
||||
*/
|
||||
public JsecBasicPermission(String target, Collection actions) {
|
||||
this.target = target;
|
||||
|
||||
// Copy the provided collection of actions.
|
||||
this.actions = new HashSet(actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable set of this permission's actions.
|
||||
*/
|
||||
public Set getActions() {
|
||||
return Collections.unmodifiableSet(this.actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this permission's actions as a comma-separated string,
|
||||
* for example 'view,create,modify,delete'.
|
||||
*/
|
||||
public String getActionsString() {
|
||||
// Delayed initialisation of the actions string.
|
||||
if (this.actionsString == null) {
|
||||
// Convert the set of actions to a string so that a standard
|
||||
// delimiter is always used.
|
||||
this.actionsString = actionsToString(this.actions);
|
||||
}
|
||||
|
||||
return this.actionsString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this permission implies the given
|
||||
* one, otherwise <code>false</code>. This method checks that this
|
||||
* permission has the same target as the given permission and a
|
||||
* super-set of the actions. The wildcard matches all targets and
|
||||
* all actions.
|
||||
*/
|
||||
public boolean implies(Permission p) {
|
||||
boolean implies = (p instanceof JsecBasicPermission);
|
||||
|
||||
if (implies) {
|
||||
// Check the target strings are the same.
|
||||
JsecBasicPermission perm = (JsecBasicPermission) p;
|
||||
if (this.target == null) {
|
||||
implies = perm.target == null;
|
||||
}
|
||||
else if (!this.target.equals(WILDCARD)) {
|
||||
implies = this.target.equals(perm.target);
|
||||
}
|
||||
|
||||
// Now check the actions (unless the current permission
|
||||
// includes the wildcard, which means that is implies
|
||||
// all other actions).
|
||||
if (implies && !this.actions.contains(WILDCARD)) {
|
||||
implies = this.actions.containsAll(perm.actions);
|
||||
}
|
||||
}
|
||||
|
||||
return implies;
|
||||
}
|
||||
|
||||
// Custom equals() method.
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof JsecBasicPermission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JsecBasicPermission p = (JsecBasicPermission) obj;
|
||||
return (this.target == null ? p.target == null : this.target.equals(p.target)) &&
|
||||
this.actions.equals(p.actions);
|
||||
}
|
||||
|
||||
// Custom hashCode() method.
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = (this.target != null ? this.target.hashCode() : 0);
|
||||
result = 31 * result + this.actions.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a delimiter-separated string of actions into a set of
|
||||
* actions. Supported delimiters are ',', ';', and whitespace.
|
||||
*/
|
||||
protected Set actionsStringToSet(String actions) {
|
||||
return new HashSet(Arrays.asList(actions.split("[,;\\s][\\s]*")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a collection of actions into a comma-separated string.
|
||||
* For example, 'view,edit,create,delete'. Note that there is no
|
||||
* whitespace in the resulting string.
|
||||
*/
|
||||
protected String actionsToString(Collection actions) {
|
||||
StringBuffer buffer = new StringBuffer(actions.size() * 10);
|
||||
for (Iterator iter = actions.iterator(); iter.hasNext();) {
|
||||
buffer.append(iter.next()).append(',');
|
||||
}
|
||||
|
||||
return buffer.substring(0, buffer.length() - 1);
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 Peter Ledbrook.
|
||||
*
|
||||
* 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.jsecurity.grails;
|
||||
|
||||
import org.jsecurity.realm.Realm;
|
||||
import org.jsecurity.authz.AuthorizationException;
|
||||
import org.jsecurity.authz.permission.WildcardPermission;
|
||||
import org.jsecurity.subject.PrincipalCollection;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Adapter for the RealmWrapper which has problems implementing the
|
||||
* "String..." methods under JDK 1.5. So, these methods automatically
|
||||
* convert the strings into WildcardPermission instances.
|
||||
*/
|
||||
public abstract class RealmAdapter implements Realm {
|
||||
public void checkPermission(PrincipalCollection principal, String s) throws AuthorizationException {
|
||||
checkPermission(principal, new WildcardPermission(s));
|
||||
}
|
||||
|
||||
public void checkPermissions(PrincipalCollection principal, String... strings) throws AuthorizationException {
|
||||
checkPermissions(principal, toPermissionList(strings));
|
||||
}
|
||||
|
||||
public boolean isPermitted(PrincipalCollection principal, String s) {
|
||||
return isPermitted(principal, new WildcardPermission(s));
|
||||
}
|
||||
|
||||
public boolean[] isPermitted(PrincipalCollection principal, String... strings) {
|
||||
return isPermitted(principal, toPermissionList(strings));
|
||||
}
|
||||
|
||||
public boolean isPermittedAll(PrincipalCollection principal, String... strings) {
|
||||
return isPermittedAll(principal, toPermissionList(strings));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of string permissions into a list of
|
||||
* {@link WildcardPermission} instances.
|
||||
*/
|
||||
private List toPermissionList(String[] strings) {
|
||||
List permissions = new ArrayList(strings.length);
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
permissions.add(new WildcardPermission(strings[i]));
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 Peter Ledbrook.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Peter Ledbrook.
|
||||
*
|
||||
* 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.jsecurity.grails;
|
||||
|
||||
import org.codehaus.groovy.grails.commons.ArtefactHandlerAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final class RealmArtefactHandler extends ArtefactHandlerAdapter {
|
||||
public static final String TYPE = "Realm";
|
||||
|
||||
public RealmArtefactHandler() {
|
||||
super(TYPE, RealmGrailsClass.class, DefaultRealmGrailsClass.class, null);
|
||||
}
|
||||
|
||||
public boolean isArtefactClass(Class clazz) {
|
||||
return clazz != null && clazz.getName().endsWith(TYPE);
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 Peter Ledbrook.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Peter Ledbrook.
|
||||
*
|
||||
* 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.jsecurity.grails;
|
||||
|
||||
import org.codehaus.groovy.grails.commons.InjectableGrailsClass;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface RealmGrailsClass extends InjectableGrailsClass{
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
import org.jsecurity.authc.AccountException
|
||||
import org.jsecurity.authc.IncorrectCredentialsException
|
||||
import org.jsecurity.authc.UnknownAccountException
|
||||
import org.jsecurity.authc.SimpleAccount
|
||||
|
||||
class @realm.name@ {
|
||||
static authTokenClass = org.jsecurity.authc.UsernamePasswordToken
|
||||
|
||||
def credentialMatcher
|
||||
|
||||
def authenticate(authToken) {
|
||||
log.info "Attempting to authenticate ${authToken.username} in DB realm..."
|
||||
def username = authToken.username
|
||||
|
||||
// Null username is invalid
|
||||
if (username == null) {
|
||||
throw new AccountException('Null usernames are not allowed by this realm.')
|
||||
}
|
||||
|
||||
// Get the user with the given username. If the user is not
|
||||
// found, then they don't have an account and we throw an
|
||||
// exception.
|
||||
def user = @domain.prefix@User.findByUsername(username)
|
||||
if (!user) {
|
||||
throw new UnknownAccountException("No account found for user [${username}]")
|
||||
}
|
||||
|
||||
log.info "Found user '${user.username}' in DB"
|
||||
|
||||
// Now check the user's password against the hashed value stored
|
||||
// in the database.
|
||||
def account = new SimpleAccount(username, user.passwordHash, "@realm.name@")
|
||||
if (!credentialMatcher.doCredentialsMatch(authToken, account)) {
|
||||
log.info 'Invalid password (DB realm)'
|
||||
throw new IncorrectCredentialsException("Invalid password for user '${username}'")
|
||||
}
|
||||
|
||||
return account
|
||||
}
|
||||
|
||||
def hasRole(principal, roleName) {
|
||||
def criteria = @domain.prefix@UserRoleRel.createCriteria()
|
||||
def roles = criteria.list {
|
||||
role {
|
||||
eq('name', roleName)
|
||||
}
|
||||
user {
|
||||
eq('username', principal)
|
||||
}
|
||||
}
|
||||
|
||||
return roles.size() > 0
|
||||
}
|
||||
|
||||
def hasAllRoles(principal, roles) {
|
||||
def criteria = @domain.prefix@UserRoleRel.createCriteria()
|
||||
def r = criteria.list {
|
||||
role {
|
||||
'in'('name', roles)
|
||||
}
|
||||
user {
|
||||
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 criteria = @domain.prefix@UserPermissionRel.createCriteria()
|
||||
def permissions = criteria.list {
|
||||
user {
|
||||
eq('username', principal)
|
||||
}
|
||||
permission {
|
||||
eq('type', requiredPermission.class.name)
|
||||
}
|
||||
}
|
||||
|
||||
// Try each of the permissions found and see whether any of
|
||||
// them confer the required permission.
|
||||
def retval = permissions?.find { rel ->
|
||||
// Create a real permission instance from the database
|
||||
// permission.
|
||||
def perm = null
|
||||
def constructor = findConstructor(rel.permission.type)
|
||||
if (constructor.parameterTypes.size() == 2) {
|
||||
perm = constructor.newInstance(rel.target, rel.actions)
|
||||
}
|
||||
else if (constructor.parameterTypes.size() == 1) {
|
||||
perm = constructor.newInstance(rel.target)
|
||||
}
|
||||
else {
|
||||
log.error "Unusable permission: ${rel.permission.type}"
|
||||
return false
|
||||
}
|
||||
|
||||
// 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?
|
||||
//
|
||||
// First, find the roles that the user has.
|
||||
def user = @domain.prefix@User.findByUsername(principal)
|
||||
def roles = @domain.prefix@UserRoleRel.findAllByUser(user)
|
||||
|
||||
// If the user has no roles, then he obviously has no permissions
|
||||
// via roles.
|
||||
if (roles.isEmpty()) return false
|
||||
|
||||
// Get the permissions from the roles that the user does have.
|
||||
criteria = @domain.prefix@RolePermissionRel.createCriteria()
|
||||
def results = criteria.list {
|
||||
'in'('role', roles.collect { it.role })
|
||||
permission {
|
||||
eq('type', requiredPermission.class.name)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 { rel ->
|
||||
def perm = null
|
||||
def constructor = findConstructor(rel.permission.type)
|
||||
if (constructor.parameterTypes.size() == 2) {
|
||||
perm = constructor.newInstance(rel.target, rel.actions)
|
||||
}
|
||||
else if (constructor.parameterTypes.size() == 1) {
|
||||
perm = constructor.newInstance(rel.target)
|
||||
}
|
||||
else {
|
||||
log.error "Unusable permission: ${rel.permission.type}"
|
||||
return false
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
def findConstructor(className) {
|
||||
// Load the required permission class.
|
||||
def clazz = this.class.classLoader.loadClass(className)
|
||||
|
||||
// Check the available constructors. If any take two
|
||||
// string parameters, we use that one and pass in the
|
||||
// target and actions string. Otherwise we try a single
|
||||
// parameter constructor and pass in just the target.
|
||||
def preferredConstructor = null
|
||||
def fallbackConstructor = null
|
||||
clazz.declaredConstructors.each { constructor ->
|
||||
def numParams = constructor.parameterTypes.size()
|
||||
if (numParams == 2) {
|
||||
if (constructor.parameterTypes[0].equals(String) &&
|
||||
constructor.parameterTypes[1].equals(String)) {
|
||||
preferredConstructor = constructor
|
||||
}
|
||||
}
|
||||
else if (numParams == 1) {
|
||||
if (constructor.parameterTypes[0].equals(String)) {
|
||||
fallbackConstructor = constructor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (preferredConstructor != null ? preferredConstructor : fallbackConstructor)
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
import javax.naming.AuthenticationException
|
||||
import javax.naming.Context
|
||||
import javax.naming.NamingException
|
||||
import javax.naming.directory.BasicAttribute
|
||||
import javax.naming.directory.BasicAttributes
|
||||
import javax.naming.directory.InitialDirContext
|
||||
|
||||
import org.jsecurity.authc.AccountException
|
||||
import org.jsecurity.authc.CredentialsException
|
||||
import org.jsecurity.authc.IncorrectCredentialsException
|
||||
import org.jsecurity.authc.UnknownAccountException
|
||||
|
||||
/**
|
||||
* Simple realm that authenticates users against an LDAP server.
|
||||
*/
|
||||
class @realm.name@ {
|
||||
static authTokenClass = org.jsecurity.authc.UsernamePasswordToken
|
||||
|
||||
def grailsApplication
|
||||
|
||||
def authenticate(authToken) {
|
||||
log.info "Attempting to authenticate ${authToken.username} in LDAP realm..."
|
||||
def username = authToken.username
|
||||
def password = new String(authToken.password)
|
||||
|
||||
// Get LDAP config for application. Use defaults when no config
|
||||
// is provided.
|
||||
def appConfig = grailsApplication.config
|
||||
def ldapUrls = appConfig.ldap.server.url ?: [ "ldap://localhost:389/" ]
|
||||
def searchBase = appConfig.ldap.search.base ?: ""
|
||||
def searchUser = appConfig.ldap.search.user ?: ""
|
||||
def searchPass = appConfig.ldap.search.pass ?: ""
|
||||
def usernameAttribute = appConfig.ldap.username.attribute ?: "uid"
|
||||
def skipAuthc = appConfig.ldap.skip.authentication ?: false
|
||||
def skipCredChk = appConfig.ldap.skip.credentialsCheck ?: false
|
||||
def allowEmptyPass = appConfig.ldap.allowEmptyPasswords != [:] ? appConfig.ldap.allowEmptyPasswords : true
|
||||
|
||||
// Skip authentication ?
|
||||
if (skipAuthc) {
|
||||
log.info "Skipping authentication in development mode."
|
||||
return username
|
||||
}
|
||||
|
||||
// Null username is invalid
|
||||
if (username == null) {
|
||||
throw new AccountException("Null usernames are not allowed by this realm.")
|
||||
}
|
||||
|
||||
// Empty username is invalid
|
||||
if (username == "") {
|
||||
throw new AccountException("Empty usernames are not allowed by this realm.")
|
||||
}
|
||||
|
||||
// Allow empty passwords ?
|
||||
if (!allowEmptyPass) {
|
||||
// Null password is invalid
|
||||
if (password == null) {
|
||||
throw new CredentialsException("Null password are not allowed by this realm.")
|
||||
}
|
||||
|
||||
// empty password is invalid
|
||||
if (password == "") {
|
||||
throw new CredentialsException("Empty passwords are not allowed by this realm.")
|
||||
}
|
||||
}
|
||||
|
||||
// Accept strings and GStrings for convenience, but convert to
|
||||
// a list.
|
||||
if (ldapUrls && !(ldapUrls instanceof Collection)) {
|
||||
ldapUrls = [ ldapUrls ]
|
||||
}
|
||||
|
||||
// Set up the configuration for the LDAP search we are about
|
||||
// to do.
|
||||
def env = new Hashtable()
|
||||
env[Context.INITIAL_CONTEXT_FACTORY] = "com.sun.jndi.ldap.LdapCtxFactory"
|
||||
if (searchUser) {
|
||||
// Non-anonymous access for the search.
|
||||
env[Context.SECURITY_AUTHENTICATION] = "simple"
|
||||
env[Context.SECURITY_PRINCIPAL] = searchUser
|
||||
env[Context.SECURITY_CREDENTIALS] = searchPass
|
||||
}
|
||||
|
||||
// Find an LDAP server that we can connect to.
|
||||
def ctx
|
||||
def urlUsed = ldapUrls.find { url ->
|
||||
log.info "Trying LDAP server ${url} ..."
|
||||
env[Context.PROVIDER_URL] = url
|
||||
|
||||
// If an exception occurs, log it.
|
||||
try {
|
||||
ctx = new InitialDirContext(env)
|
||||
return true
|
||||
}
|
||||
catch (NamingException e) {
|
||||
log.error "Could not connect to ${url}: ${e}"
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (!urlUsed) {
|
||||
def msg = 'No LDAP server available.'
|
||||
log.error msg
|
||||
throw new org.jsecurity.authc.AuthenticationException(msg)
|
||||
}
|
||||
|
||||
// Look up the DN for the LDAP entry that has a 'uid' value
|
||||
// matching the given username.
|
||||
def matchAttrs = new BasicAttributes(true)
|
||||
matchAttrs.put(new BasicAttribute(usernameAttribute, username))
|
||||
|
||||
def result = ctx.search(searchBase, matchAttrs)
|
||||
if (!result.hasMore()) {
|
||||
throw new UnknownAccountException("No account found for user [${username}]")
|
||||
}
|
||||
|
||||
// Skip credentials check ?
|
||||
if (skipCredChk) {
|
||||
log.info "Skipping credentials check in development mode."
|
||||
return username
|
||||
}
|
||||
|
||||
// Now connect to the LDAP server again, but this time use
|
||||
// authentication with the principal associated with the given
|
||||
// username.
|
||||
def searchResult = result.next()
|
||||
env[Context.SECURITY_AUTHENTICATION] = "simple"
|
||||
env[Context.SECURITY_PRINCIPAL] = searchResult.nameInNamespace
|
||||
env[Context.SECURITY_CREDENTIALS] = password
|
||||
|
||||
try {
|
||||
new InitialDirContext(env)
|
||||
return username
|
||||
}
|
||||
catch (AuthenticationException ex) {
|
||||
log.info "Invalid password"
|
||||
throw new IncorrectCredentialsException("Invalid password for user '${username}'")
|
||||
}
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
import org.jsecurity.authc.AuthenticationException
|
||||
import org.jsecurity.authc.UsernamePasswordToken
|
||||
import org.jsecurity.SecurityUtils
|
||||
|
||||
class AuthController {
|
||||
def jsecSecurityManager
|
||||
|
||||
def index = { redirect(action: 'login', params: params) }
|
||||
|
||||
def login = {
|
||||
return [ username: params.username, rememberMe: (params.rememberMe != null), targetUri: params.targetUri ]
|
||||
}
|
||||
|
||||
def signIn = {
|
||||
def authToken = new UsernamePasswordToken(params.username, params.password)
|
||||
|
||||
// Support for "remember me"
|
||||
if (params.rememberMe) {
|
||||
authToken.rememberMe = true
|
||||
}
|
||||
|
||||
try{
|
||||
// Perform the actual login. An AuthenticationException
|
||||
// will be thrown if the username is unrecognised or the
|
||||
// password is incorrect.
|
||||
this.jsecSecurityManager.login(authToken)
|
||||
|
||||
// If a controller redirected to this page, redirect back
|
||||
// to it. Otherwise redirect to the root URI.
|
||||
def targetUri = params.targetUri ?: "/"
|
||||
|
||||
log.info "Redirecting to '${targetUri}'."
|
||||
redirect(uri: targetUri)
|
||||
}
|
||||
catch (AuthenticationException ex){
|
||||
// Authentication failed, so display the appropriate message
|
||||
// on the login page.
|
||||
log.info "Authentication failure for user '${params.username}'."
|
||||
flash.message = message(code: "login.failed")
|
||||
|
||||
// Keep the username and "remember me" setting so that the
|
||||
// user doesn't have to enter them again.
|
||||
def m = [ username: params.username ]
|
||||
if (params.rememberMe) {
|
||||
m['rememberMe'] = true
|
||||
}
|
||||
|
||||
// Remember the target URI too.
|
||||
if (params.targetUri) {
|
||||
m['targetUri'] = params.targetUri
|
||||
}
|
||||
|
||||
// Now redirect back to the login page.
|
||||
redirect(action: 'login', params: m)
|
||||
}
|
||||
}
|
||||
|
||||
def signOut = {
|
||||
// Log the user out of the application.
|
||||
SecurityUtils.subject?.logout()
|
||||
|
||||
// For now, redirect back to the home page.
|
||||
redirect(uri: '/')
|
||||
}
|
||||
|
||||
def unauthorized = {
|
||||
render 'You do not have permission to access this page.'
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
class @domain.prefix@Permission {
|
||||
String type
|
||||
String possibleActions
|
||||
|
||||
static constraints = {
|
||||
type(nullable: false, blank: false, unique: true)
|
||||
possibleActions(nullable:false, blank: false)
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
class @domain.prefix@Role {
|
||||
String name
|
||||
|
||||
static constraints = {
|
||||
name(nullable: false, blank: false, unique: true)
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
class @domain.prefix@RolePermissionRel {
|
||||
@domain.prefix@Role role
|
||||
@domain.prefix@Permission permission
|
||||
String target
|
||||
String actions
|
||||
|
||||
static constraints = {
|
||||
actions(nullable: false, blank: false)
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
class @domain.prefix@User {
|
||||
String username
|
||||
String passwordHash
|
||||
|
||||
static constraints = {
|
||||
username(nullable: false, blank: false)
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
class @domain.prefix@UserPermissionRel {
|
||||
@domain.prefix@User user
|
||||
@domain.prefix@Permission permission
|
||||
String target
|
||||
String actions
|
||||
|
||||
static constraints = {
|
||||
target(nullable: true, blank: false)
|
||||
actions(nullable: false, blank: false)
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
class @domain.prefix@UserRoleRel {
|
||||
@domain.prefix@User user
|
||||
@domain.prefix@Role role
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="layout" content="main" />
|
||||
<title>Login</title>
|
||||
</head>
|
||||
<body>
|
||||
<g:if test="${flash.message}">
|
||||
<div class="message">${flash.message}</div>
|
||||
</g:if>
|
||||
<g:form action="signIn">
|
||||
<input type="hidden" name="targetUri" value="${targetUri}" />
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Username:</td>
|
||||
<td><input type="text" name="username" value="${username}" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Password:</td>
|
||||
<td><input type="password" name="password" value="" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Remember me?:</td>
|
||||
<td><g:checkBox name="rememberMe" value="${rememberMe}" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td />
|
||||
<td><input type="submit" value="Sign in" /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</g:form>
|
||||
</body>
|
||||
</html>
|
@ -24,10 +24,15 @@ import org.apache.commons.lang.RandomStringUtils;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bigbluebutton.web.domain.Conference;
|
||||
|
||||
public class DynamicConference extends Conference {
|
||||
|
||||
public class DynamicConference {
|
||||
Date dateCreated
|
||||
Date lastUpdated
|
||||
String createdBy
|
||||
String updatedBy
|
||||
String name
|
||||
Integer conferenceNumber
|
||||
|
||||
Date storedTime;
|
||||
Date startTime;
|
||||
Date endTime;
|
||||
|
@ -1 +1 @@
|
||||
This page is no longer available, please use the api
|
||||
This page is no longer available, please use the api.
|
||||
|
Loading…
Reference in New Issue
Block a user