blob: e9b341734eec2910fedf28b33406e515ceba9838 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* https://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 grails.plugin.springsecurity.ui
import grails.core.GrailsApplication
import grails.gorm.transactions.Transactional
import grails.plugin.springsecurity.SpringSecurityUtils
import grails.plugin.springsecurity.ui.strategy.AclStrategy
import grails.plugin.springsecurity.ui.strategy.ErrorsStrategy
import grails.plugin.springsecurity.ui.strategy.MailStrategy
import grails.plugin.springsecurity.ui.strategy.PersistentLoginStrategy
import grails.plugin.springsecurity.ui.strategy.PropertiesStrategy
import grails.plugin.springsecurity.ui.strategy.QueryStrategy
import grails.plugin.springsecurity.ui.strategy.RegistrationCodeStrategy
import grails.plugin.springsecurity.ui.strategy.RequestmapStrategy
import grails.plugin.springsecurity.ui.strategy.RoleStrategy
import grails.plugin.springsecurity.ui.strategy.UserStrategy
import grails.util.GrailsNameUtils
import groovy.util.logging.Slf4j
import org.springframework.context.MessageSource
import org.springframework.context.i18n.LocaleContextHolder
import org.springframework.security.core.userdetails.UserCache
import org.springframework.transaction.TransactionStatus
import org.springframework.util.ClassUtils
import java.text.SimpleDateFormat
/**
* Helper methods for UI management.
*
* @author <a href='mailto:burt@burtbeckwith.com'>Burt Beckwith</a>
*/
@Slf4j
class SpringSecurityUiService implements AclStrategy, ErrorsStrategy, PersistentLoginStrategy,
PropertiesStrategy, QueryStrategy, RegistrationCodeStrategy,
RequestmapStrategy, RoleStrategy, UserStrategy {
public static final String DATE_FORMAT = 'd MMM yyyy HH:mm:ss'
protected static final String ACL_CLASS_NAME = 'grails.plugin.springsecurity.acl.AclClass'
protected static final String ACL_ENTRY_NAME = 'grails.plugin.springsecurity.acl.AclEntry'
protected static final String ACL_OBJECT_IDENTITY_NAME = 'grails.plugin.springsecurity.acl.AclObjectIdentity'
protected static final String ACL_SID_NAME = 'grails.plugin.springsecurity.acl.AclSid'
protected Map<Class<?>, Map<String, String>> classMappings
/** Dependency injection for the 'uiErrorsStrategy' bean. */
ErrorsStrategy uiErrorsStrategy
/** Dependency injection for the 'uiMailStrategy' bean. */
MailStrategy uiMailStrategy
/** Dependency injection for the 'uiPropertiesStrategy' bean. */
PropertiesStrategy uiPropertiesStrategy
GrailsApplication grailsApplication
MessageSource messageSource
def springSecurityService
UserCache userCache
@Transactional
def saveAclClass(Map properties) {
save properties, AclClass, 'saveAclClass', transactionStatus
}
@Transactional
void updateAclClass(Map properties, aclClass) {
save properties, aclClass, 'updateAclClass', transactionStatus
}
@Transactional
void deleteAclClass(aclClass) {
// will fail if there are FK references
delete aclClass, 'deleteAclClass', transactionStatus
}
@Transactional
def saveAclEntry(Map properties) {
save(properties, AclEntry, 'saveAclEntry', transactionStatus) { aclEntry ->
removeIfTransient aclEntry, 'aclObjectIdentity', 'sid'
}
}
@Transactional
void updateAclEntry(Map properties, aclEntry) {
save(properties, aclEntry, 'updateAclEntry', transactionStatus) {
removeIfTransient aclEntry, 'aclObjectIdentity', 'sid'
}
}
@Transactional
void deleteAclEntry(aclEntry) {
delete aclEntry, 'deleteAclEntry', transactionStatus
}
@Transactional
def saveAclObjectIdentity(Map properties) {
save(properties, AclObjectIdentity, 'saveAclObjectIdentity', transactionStatus) { aclObjectIdentity ->
removeIfTransient aclObjectIdentity, 'aclClass', 'owner', 'parent'
}
}
@Transactional
void updateAclObjectIdentity(Map properties, aclObjectIdentity) {
save properties, aclObjectIdentity, 'updateAclObjectIdentity', transactionStatus
}
@Transactional
void deleteAclObjectIdentity(aclObjectIdentity) {
// will fail if there are FK references
delete aclObjectIdentity, 'deleteAclObjectIdentity', transactionStatus
}
@Transactional
def saveAclSid(Map properties) {
save properties, AclSid, 'saveAclSid', transactionStatus
}
@Transactional
void updateAclSid(Map properties, aclSid) {
save properties, aclSid, 'updateAclSid', transactionStatus
}
@Transactional
void deleteAclSid(aclSid) {
// will fail if there are FK references
delete aclSid, 'deleteAclSid', transactionStatus
}
@Transactional
void updatePersistentLogin(Map properties, persistentLogin) {
properties = [:] + properties
if (properties.lastUsed && properties.lastUsed instanceof String) {
Calendar c = Calendar.instance
c.time = new SimpleDateFormat(DATE_FORMAT).parse(properties.lastUsed)
properties.lastUsed = c.time
}
save properties, persistentLogin, 'updatePersistentLogin', transactionStatus
}
@Transactional
void deletePersistentLogin(persistentLogin) {
delete persistentLogin, 'deletePersistentLogin', transactionStatus
}
@Transactional
void updateRegistrationCode(Map properties, RegistrationCode registrationCode) {
save properties, registrationCode, 'updateRegistrationCode', transactionStatus
}
@Transactional
void deleteRegistrationCode(RegistrationCode registrationCode) {
delete registrationCode, 'deleteRegistrationCode', transactionStatus
}
@Transactional
RegistrationCode register(user, String password) {
save password: encodePassword(password), user, 'register', transactionStatus
if (user.hasErrors()) {
return
}
String username = uiPropertiesStrategy.getProperty(user, 'username')
save username: username, RegistrationCode, 'register', transactionStatus
}
def createUser(RegisterCommand command) {
uiPropertiesStrategy.setProperties(
email: command.email, username: command.username, accountLocked: true, enabled: true, User, null)
}
/*Abstracted so this method can be used in other applications and if we determine to use another matching stragery later we can update as needed
*/
boolean doesAnswerMatch(String val1, String val2) {
springSecurityService.passwordEncoder.matches(val2, val1)
}
@Transactional
def validateForgotPasswordExtraSecurity(params,user,forgotPasswordExtraValidationDomainClassName,forgotPasswordExtraValidation,String validationUserLookUpProperty) {
Boolean isvalid = true
String instance
def domain = grailsApplication.getClassForName(forgotPasswordExtraValidationDomainClassName)
if(!(domain instanceof Object)) {
return [false,[errorMsg:messageSource.getMessage('spring.security.ui.securityQuestions.extraValidationString.config',null,'Domain Not Found',LocaleContextHolder.getLocale())]]
}
List<HashMap> rtnValidations = []
forgotPasswordExtraValidation?.eachWithIndex{it,idx->
HashMap inst = forgotPasswordExtraValidation.getAt(idx)
rtnValidations[idx] = [:]
instance = this.getProperty(domain.findWhere((validationUserLookUpProperty): user),inst.prop)
rtnValidations[idx].valueTxt = params.get(inst.prop)
if (!instance || instance.size() == 0 || ! this.doesAnswerMatch(instance,params.get(inst.prop)?.toLowerCase()) ) {
rtnValidations[idx].errorMsg = messageSource.getMessage('spring.security.ui.securityQuestions.extraValidationString.notequal',null,'Not Equal',LocaleContextHolder.getLocale())
isvalid = false
}
idx++
}
[isvalid,rtnValidations]
}
@Transactional
def verifyRegistration(String token) {
def conf = SpringSecurityUtils.securityConfig
RegistrationCode registrationCode = token ? RegistrationCode.findByToken(token) : null
def registerPostRegisterUrl = conf.ui.register.postRegisterUrl ?: ''
def successHandlerDefaultTargetUrl = conf.successHandler.defaultTargetUrl ?: '/'
if (!registrationCode) {
return [flashType:'error',flashmsg:'spring.security.ui.register.badCode',redirectmsg:successHandlerDefaultTargetUrl]
}
def user = this.finishRegistration(registrationCode)
if (!user || user.hasErrors()) {
return [flashType:'error',flashmsg:'spring.security.ui.register.badCode',redirectmsg:successHandlerDefaultTargetUrl]
}
[flashType:'message', flashmsg:'spring.security.ui.register.complete',redirectmsg:registerPostRegisterUrl ?: successHandlerDefaultTargetUrl]
}
@Transactional
def finishRegistration(RegistrationCode registrationCode) {
def user = findUserByUsername(registrationCode.username)
if (!user) {
return
}
save accountLocked: false, user, 'finishRegistration', transactionStatus
if (!user.hasErrors()) {
addRoles user, registerDefaultRoleNames
delete registrationCode, 'finishRegistration', transactionStatus
springSecurityService.reauthenticate registrationCode.username
}
user
}
@Transactional
RegistrationCode sendForgotPasswordMail(String username) {
sendForgotPasswordMail(username, null, null,false)
}
@Transactional
RegistrationCode sendForgotPasswordMail(String username, String emailAddress, Boolean sendMail) {
sendForgotPasswordMail(username, emailAddress, null,sendMail)
}
@Transactional
RegistrationCode sendForgotPasswordMail(String username, String emailAddress, Closure emailBodyGenerator) {
sendForgotPasswordMail(username, emailAddress, emailBodyGenerator,true)
}
@Transactional
RegistrationCode sendForgotPasswordMail(String username, String emailAddress, Closure emailBodyGenerator, Boolean sendMail) {
RegistrationCode registrationCode = save(username: username, RegistrationCode, 'sendForgotPasswordMail', transactionStatus)
if (!registrationCode.hasErrors() && sendMail) {
uiMailStrategy.sendForgotPasswordMail(
to: emailAddress,
from: forgotPasswordEmailFrom,
subject: forgotPasswordEmailSubject,
html: emailBodyGenerator(registrationCode.token))
}
registrationCode
}
@Transactional
def resetPassword(ResetPasswordCommand command, RegistrationCode registrationCode) {
def user = findUserByUsername(registrationCode.username)
save password: encodePassword(command.password), user, 'resetPassword', transactionStatus
if (!user.hasErrors()) {
delete registrationCode, 'resetPassword', transactionStatus
springSecurityService.reauthenticate registrationCode.username
}
user
}
@Transactional
def saveRole(Map properties) {
save properties, Role, 'saveRole', transactionStatus
}
@Transactional
void updateRole(Map properties, role) {
updateKeys properties, role
try {
springSecurityService.updateRole role, properties
}
catch (e) {
uiErrorsStrategy.handleException e, role, properties, this, 'updateRole', transactionStatus
return
}
if (role.hasErrors()) {
uiErrorsStrategy.handleValidationErrors role, this, 'updateRole', transactionStatus
}
}
@Transactional
void deleteRole(role) {
try {
UserRole.removeAll role
springSecurityService.deleteRole role
}
catch (e) {
uiErrorsStrategy.handleException e, role, null, this, 'deleteRole', transactionStatus
}
}
@Transactional
def saveRequestmap(Map properties) {
save properties, Requestmap, 'saveRequestmap', transactionStatus
}
@Transactional
void updateRequestmap(Map properties, requestmap) {
save properties, requestmap, 'updateRequestmap', transactionStatus
if (!requestmap.hasErrors()) {
springSecurityService.clearCachedRequestmaps()
}
}
@Transactional
void deleteRequestmap(requestmap) {
delete requestmap, 'deleteRequestmap', transactionStatus
springSecurityService.clearCachedRequestmaps()
}
@Transactional
def saveUser(Map properties, List<String> roleNames, String password) {
def user = uiPropertiesStrategy.setProperties(properties, User, transactionStatus)
if (password) {
updatePassword user, password, transactionStatus
}
save [:], user, 'saveUser', transactionStatus
if (!user.hasErrors()) {
addRoles user, roleNames
}
user
}
@Transactional
void updateUser(Map properties, user, List<String> roleNames) {
String oldPassword = uiPropertiesStrategy.getProperty(user, 'password')
uiPropertiesStrategy.setProperties properties, user, transactionStatus
if (properties.password && properties.password != oldPassword) {
updatePassword user, properties.password, transactionStatus
}
save [:], user, 'updateUser', transactionStatus
if (user.hasErrors()) {
return
}
updateUserRoles user, roleNames, transactionStatus
removeUserFromCache user
}
@Transactional
void deleteUser(user) {
UserRole.removeAll user
delete user, 'deleteUser', transactionStatus
removeUserFromCache user
}
protected void addRoles(user, List<String> roleNames) {
String authorityNameField = uiPropertiesStrategy.paramNameToPropertyName('authority', 'role')
try {
for (String roleName in roleNames) {
UserRole.create user, Role.findWhere((authorityNameField): roleName)
}
}
catch (e) {
uiErrorsStrategy.handleException e, user, null, this, 'addRoles', transactionStatus
}
}
@Transactional
protected void addUserRoles(user, Set rolesToAdd) {
if (!user || !rolesToAdd) {
return
}
List<String> roleNames = []
rolesToAdd.each { role ->
roleNames << role.authority
}
addRoles(user, roleNames)
}
protected void updateUserRoles(user, List<String> roleNames, TransactionStatus transactionStatus) {
String authorityNameField = uiPropertiesStrategy.paramNameToPropertyName('authority', 'role')
try {
String dynamicFinder = "findAllBy".concat(authorityNameField.capitalize()).concat("InList")
List selectedRoles = Role."${dynamicFinder}"(roleNames)
Set originalRoles = user.authorities
Set rolesToRemove = originalRoles - selectedRoles
Set rolesToAdd = selectedRoles - originalRoles
removeUserRoles(user, rolesToRemove)
addUserRoles(user, rolesToAdd)
}
catch (e) {
uiErrorsStrategy.handleException e, user, null, this, 'updateUserRoles', transactionStatus
}
}
protected void removeUserRoles(user, Set rolesToRemove) {
if (!user || !rolesToRemove) {
return
}
try {
rolesToRemove.each { role ->
removeUserRoleAndReturnBoolean(user, role)
}
}
catch (e) {
uiErrorsStrategy.handleException e, user, null, this, 'removeUserRoles', transactionStatus
}
}
@Transactional
boolean removeUserRoleAndReturnBoolean(def user, def role) {
UserRole.remove user, role
}
@Transactional
Number removeUserRole(def u, def r) {
UserRole.where { user == u && role == r }.deleteAll()
}
protected void removeUserFromCache(user) {
userCache.removeUserFromCache uiPropertiesStrategy.getProperty(user, 'username')
}
protected void delete(instance, String methodName, TransactionStatus transactionStatus) {
assert transactionStatus
try {
instance.delete()
}
catch (e) {
uiErrorsStrategy.handleException e, instance, null, this, methodName, transactionStatus
}
}
Map<Class<?>, Map<String, String>> findClassMappings() {
def conf = SpringSecurityUtils.securityConfig
def mappings = [:]
def userLookup = conf.userLookup
mappings[User] = [
username: userLookup.usernamePropertyName ?: '',
enabled: userLookup.enabledPropertyName ?: '',
password: userLookup.passwordPropertyName ?: '',
authorities: userLookup.authoritiesPropertyName ?: '',
accountExpired: userLookup.accountExpiredPropertyName ?: '',
accountLocked: userLookup.accountLockedPropertyName ?: '',
passwordExpired: userLookup.passwordExpiredPropertyName ?: ''].asImmutable()
mappings[Role] = [authority: conf.authority.nameField ?: ''].asImmutable()
def requestMap = conf.requestMap
mappings[Requestmap] = [
url: requestMap.urlField ?: '',
configAttribute: requestMap.configAttributeField ?: '',
httpMethod: requestMap.httpMethodField ?: ''].asImmutable()
mappings
}
def getProperty(instance, String paramName) {
if (!instance) return
if (paramName.endsWith('.id')) {
paramName = paramName[0..-4]
}
def value = instance
String currentPath = ''
for (String paramNamePart in paramName.split('\\.')) {
currentPath += paramNamePart
String classPropertyName = GrailsNameUtils.getPropertyName(
unproxy(value.getClass()).name)
String propertyName = uiPropertiesStrategy.paramNameToPropertyName(
paramNamePart, classPropertyName)
try {
if (instance.metaClass.getMetaProperty(propertyName)?.getter) {
value = value[propertyName]
if (value == null) return
}
else {
log.error 'Attempted to read non-existent property {} in {}', currentPath as String, instance as String
return
}
}
catch (e) {
throw new InvalidValueException(propertyName, paramNamePart, value, e)
}
currentPath += '.'
}
value
}
String paramNameToPropertyName(String paramName, String controllerName) {
// Properties in the ACL classes and RegistrationCode aren't currently
// configurable, and the PersistentLogin class is generated but its
// properties also aren't configurable. Since this method is only by
// the controllers to be able to hard-code param names and lookup the
// actual domain class property name we can short-circuit the logic here.
// Additionally there's no need to support nested properties (e.g.
// 'aclClass.className' for AclObjectIdentity search) since those are
// not used in GSP for classes with configurable properties.
if (!paramName) {
return paramName
}
Class<?> clazz = domainClassesByControllerName[controllerName]
String name
if (clazz) {
String key = paramName
if (paramName.endsWith('.id')) {
key = paramName[0..-4]
}
name = classMappings[clazz][key]
}
name ?: paramName
}
def setProperties(Map data, instanceOrClass, TransactionStatus transactionStatus) {
if (instanceOrClass == null) return
updateKeys data, instanceOrClass
def instance
try {
if (instanceOrClass instanceof Class) {
instance = instanceOrClass.newInstance(data)
}
else {
instance = instanceOrClass
instance.properties = data
}
}
catch (e) {
uiErrorsStrategy.handleException e, instance, data, this, 'setProperties', transactionStatus
}
instance
}
protected void updateKeys(Map data, instanceOrClass) {
Class clazz
if (instanceOrClass instanceof Class) {
clazz = instanceOrClass
}
else {
clazz = instanceOrClass.getClass()
}
Map<String, String> mappings = classMappings[unproxy(clazz)]
if (!mappings) return
def removed = [:]
([] + data.keySet()).each { String paramName ->
String mappedKey = mappings[paramName]
if (mappedKey && mappedKey != paramName) {
removed[mappedKey] = data.remove(paramName)
}
}
data.putAll removed
}
void handleValidationErrors(bean, source, String operation, TransactionStatus transactionStatus) {
log.warn('Problem in {} at "{}" {} {} : {} {}',
source as String,
operation as String,
isAttached(bean) ? 'updating' : 'creating',
bean.getClass().simpleName,
bean as String,
beanErrors(bean))
rollbackAndDiscard bean, transactionStatus
}
String beanErrors(bean) {
StringBuilder message = new StringBuilder()
def locale = LocaleContextHolder.getLocale()
for (fieldErrors in bean.errors) {
for (error in fieldErrors.allErrors) {
message << '\n\t' << messageSource.getMessage(error, locale)
}
}
message.toString()
}
void handleException(Throwable t, bean, Map properties, source, String operation,
TransactionStatus transactionStatus) {
boolean attached = bean && !(bean instanceof CommandObject) && bean.attached
def message = new StringBuilder()
message << 'Problem in ' << source << ' at "' << operation
if (bean) {
message << '" with bean ' << bean.getClass().simpleName << ': ' << bean
}
log.error message.toString(), t
if (transactionStatus) {
rollbackAndDiscard bean, transactionStatus
}
}
protected boolean isAttached(bean) {
bean && !(bean instanceof CommandObject) && bean.attached
}
protected void rollbackAndDiscard(bean, TransactionStatus transactionStatus) {
if (bean && !(bean instanceof CommandObject)) {
bean.discard()
}
transactionStatus.setRollbackOnly()
}
String encodePassword(String password) {
if (encodePassword) {
password = springSecurityService.encodePassword(password)
}
password
}
Closure<?> buildProjection(String path, String criterionMethod, List args) {
log.debug "Building projection for path '{}': {}({})", path, criterionMethod, args.toString()
def invoker = { String projectionName, Closure<?> subcriteria ->
log.trace 'Invoking projection {}', projectionName
delegate."$projectionName"(subcriteria)
}
def closure = { ->
log.trace 'Invoking criterion {}({})', criterionMethod, args as String
delegate."$criterionMethod"(args)
}
for (String projectionName in (path.split('\\.').reverse())) {
closure = invoker.clone().curry(projectionName, closure)
}
closure
}
def runCriteria(Class<?> clazz, List<Closure<?>> criterias, Map paginateParams) {
clazz.createCriteria().list(paginateParams) {
for (Closure<?> criteria in criterias) {
criteria.delegate = delegate
criteria()
}
}
}
protected void updatePassword(user, String password, TransactionStatus transactionStatus) {
uiPropertiesStrategy.setProperties password: encodePassword(password), user, transactionStatus
}
protected Class<?> unproxy(Class<?> clazz) {
Class<?> current = clazz
while (isProxy(current)) {
current = current.superclass
}
current
}
protected boolean isProxy(Class<?> clazz) {
if (clazz.superclass == Object) {
return false
}
if (ClassUtils.isCglibProxyClass(clazz)) {
return true
}
// Javassist
clazz.interfaces.any { it.name.contains('org.hibernate.proxy.HibernateProxy') }
}
protected save(Map data, instanceOrClass, String methodName, transactionStatus, Closure callback = null) {
assert transactionStatus
def instance
try {
instance = uiPropertiesStrategy.setProperties(data, instanceOrClass, transactionStatus)
if (callback) {
callback instance
}
instance.save()
if (instance.hasErrors()) {
uiErrorsStrategy.handleValidationErrors instance, this, methodName, transactionStatus
}
}
catch (e) {
uiErrorsStrategy.handleException e, instance, data, this, methodName, transactionStatus
}
instance
}
/**
* When databinding and an object reference id isn't valid, the property will be a new
* 'transient' instance. If there are no validation errors, Hibernate will complain when
* flushing (typically with committing the transaction) 'an unsaved transient instance',
* so we remove the instance here before calling save(). If the property is nullable the
* update will succeed and the caller can handle the problem, and if it's not nullable
* this will trigger a validation error which is easier to handle than the exception
* that Hibernate throws.
*
* @param bean the bean (in practice only an AclEntry or AclObjectIdentity) since the
* other domain classes don't have FK references
* @param propertyName the property name of the child object
*/
protected void removeIfTransient(bean, String... propertyNames) {
def discardedNames = []
for (propertyName in propertyNames) {
def property = bean[propertyName]
if (property && !property.attached) {
bean[propertyName] = null
discardedNames << propertyName
}
}
if ( discardedNames ) {
log.warn 'Discarding transient properties {} from {}', discardedNames as String, bean as String
}
}
protected findUserByUsername(String username) {
User.findWhere((classMappings[User].username): username)
}
protected boolean encodePassword
protected String forgotPasswordEmailFrom
protected String forgotPasswordEmailSubject
protected List<String> registerDefaultRoleNames
protected Class<?> AclClass
protected Class<?> AclEntry
protected Class<?> AclObjectIdentity
protected Class<?> AclSid
protected Class<?> Requestmap
protected Class<?> Role
protected Class<?> User
protected Class<?> UserRole
protected Map<String, Class<?>> domainClassesByControllerName = [:]
void initialize() {
def conf = SpringSecurityUtils.securityConfig
def encode = conf.ui.encodePassword
encodePassword = encode instanceof Boolean ? encode : false
forgotPasswordEmailFrom = conf.ui.forgotPassword.emailFrom ?: ''
forgotPasswordEmailSubject = conf.ui.forgotPassword.emailSubject ?: messageSource ? messageSource.getMessage('spring.security.ui.forgotPassword.email.subject', [].toArray(), 'Password Reset', LocaleContextHolder.locale) : '' ?: ''
registerDefaultRoleNames = conf.ui.register.defaultRoleNames ?: []
def getDomainClassClass = { String name ->
if (name) return grailsApplication.getDomainClass(name)?.clazz
}
AclClass = getDomainClassClass(ACL_CLASS_NAME)
AclEntry = getDomainClassClass(ACL_ENTRY_NAME)
AclObjectIdentity = getDomainClassClass(ACL_OBJECT_IDENTITY_NAME)
AclSid = getDomainClassClass(ACL_SID_NAME)
Requestmap = getDomainClassClass(conf.requestMap.className)
Role = getDomainClassClass(conf.authority.className)
User = getDomainClassClass(conf.userLookup.userDomainClassName)
UserRole = getDomainClassClass(conf.userLookup.authorityJoinClassName)
domainClassesByControllerName = [requestmap: Requestmap, role: Role, user: User]
classMappings = uiPropertiesStrategy.findClassMappings().asImmutable()
}
}