- fixed few issues and cleaned up

This commit is contained in:
BigBlueButton 2010-07-19 20:23:28 +00:00
parent ea156fe61e
commit 333dd13d6b
43 changed files with 9 additions and 2942 deletions

View File

@ -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

View File

@ -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 }
}
}
}
}

View File

@ -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)
}
}

View 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() {

View File

@ -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[])
}
}
}
}

View File

@ -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

View File

@ -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
}
}
}
}
}

View File

@ -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
}
}

View File

@ -1 +0,0 @@
login.failed = Invalid username and/or password

View File

@ -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)
}
}

View File

@ -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>

View File

@ -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")
}

View File

@ -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])
}

View File

@ -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])
}

View File

@ -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()
}

View File

@ -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")

View File

@ -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])
}

View File

@ -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")

View File

@ -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
}
}
}

View File

@ -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)
}
}

View File

@ -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]
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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{
}

View File

@ -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)
}
}

View File

@ -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}'")
}
}
}

View File

@ -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.'
}
}

View File

@ -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)
}
}

View File

@ -1,7 +0,0 @@
class @domain.prefix@Role {
String name
static constraints = {
name(nullable: false, blank: false, unique: true)
}
}

View File

@ -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)
}
}

View File

@ -1,8 +0,0 @@
class @domain.prefix@User {
String username
String passwordHash
static constraints = {
username(nullable: false, blank: false)
}
}

View File

@ -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)
}
}

View File

@ -1,4 +0,0 @@
class @domain.prefix@UserRoleRel {
@domain.prefix@User user
@domain.prefix@Role role
}

View File

@ -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>

View File

@ -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;

View File

@ -1 +1 @@
This page is no longer available, please use the api
This page is no longer available, please use the api.