[58] | 1 | /* Copyright 2006-2009 the original author or authors. |
---|
| 2 | * |
---|
| 3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
---|
| 4 | * you may not use this file except in compliance with the License. |
---|
| 5 | * You may obtain a copy of the License at |
---|
| 6 | * |
---|
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
---|
| 8 | * |
---|
| 9 | * Unless required by applicable law or agreed to in writing, software |
---|
| 10 | * distributed under the License is distributed on an "AS IS" BASIS, |
---|
| 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
| 12 | * See the License for the specific language governing permissions and |
---|
| 13 | * limitations under the License. |
---|
| 14 | */ |
---|
| 15 | package org.grails.plugins.springsecurity.service |
---|
| 16 | |
---|
| 17 | import org.codehaus.groovy.grails.plugins.springsecurity.AuthorizeTools |
---|
| 18 | |
---|
| 19 | import org.springframework.security.context.SecurityContextHolder as SCH |
---|
| 20 | import org.springframework.security.ui.AbstractProcessingFilter as APF |
---|
| 21 | import org.springframework.security.userdetails.UserDetails |
---|
| 22 | |
---|
| 23 | /** |
---|
| 24 | * Authentication utility methods. |
---|
| 25 | * |
---|
| 26 | * @author T.Yamamoto |
---|
| 27 | * @author <a href='mailto:beckwithb@studentsonly.com'>Burt Beckwith</a> |
---|
| 28 | */ |
---|
| 29 | class AuthenticateService { |
---|
| 30 | |
---|
| 31 | boolean transactional = false |
---|
| 32 | |
---|
| 33 | private securityConfig |
---|
| 34 | |
---|
| 35 | /** dependency injection for {@link GrailsFilterInvocationDefinition} */ |
---|
| 36 | def objectDefinitionSource |
---|
| 37 | |
---|
| 38 | /** dependency injection for the password encoder */ |
---|
| 39 | def passwordEncoder |
---|
| 40 | |
---|
| 41 | /** |
---|
| 42 | * @deprecated You can invoke tags from controllers (since grails-0.6) |
---|
| 43 | */ |
---|
| 44 | boolean ifAllGranted(role) { |
---|
| 45 | return AuthorizeTools.ifAllGranted(role) |
---|
| 46 | } |
---|
| 47 | |
---|
| 48 | /** |
---|
| 49 | * @deprecated You can invoke tags from controllers (since grails-0.6) |
---|
| 50 | */ |
---|
| 51 | boolean ifNotGranted(role) { |
---|
| 52 | return AuthorizeTools.ifNotGranted(role) |
---|
| 53 | } |
---|
| 54 | |
---|
| 55 | /** |
---|
| 56 | * @deprecated You can invoke tags from controllers (since grails-0.6) |
---|
| 57 | */ |
---|
| 58 | boolean ifAnyGranted(role) { |
---|
| 59 | return AuthorizeTools.ifAnyGranted(role) |
---|
| 60 | } |
---|
| 61 | |
---|
| 62 | /** |
---|
| 63 | * Get the currently logged in user's principal. |
---|
| 64 | * @return the principal or <code>null</code> if not logged in |
---|
| 65 | */ |
---|
| 66 | def principal() { |
---|
| 67 | return SCH?.context?.authentication?.principal |
---|
| 68 | } |
---|
| 69 | |
---|
| 70 | /** |
---|
| 71 | * Get the currently logged in user's domain class. |
---|
| 72 | * @return the domain object or <code>null</code> if not logged in |
---|
| 73 | */ |
---|
| 74 | def userDomain() { |
---|
| 75 | return isLoggedIn() ? principal().domainClass : null |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | /** |
---|
| 79 | * Load the security configuration. |
---|
| 80 | * @return the config |
---|
| 81 | */ |
---|
| 82 | ConfigObject getSecurityConfig() { |
---|
| 83 | if (securityConfig == null) { |
---|
| 84 | securityConfig = AuthorizeTools.getSecurityConfig() |
---|
| 85 | } |
---|
| 86 | return securityConfig |
---|
| 87 | } |
---|
| 88 | |
---|
| 89 | /** |
---|
| 90 | * returns a MessageDigest password. |
---|
| 91 | * (changes algorithm method dynamically by param of config) |
---|
| 92 | * @deprecated use <code>encodePassword</code> instead |
---|
| 93 | */ |
---|
| 94 | String passwordEncoder(String passwd) { |
---|
| 95 | return encodePassword(passwd) |
---|
| 96 | } |
---|
| 97 | |
---|
| 98 | String encodePassword(String passwd) { |
---|
| 99 | return passwordEncoder.encodePassword(passwd, null) |
---|
| 100 | } |
---|
| 101 | |
---|
| 102 | /** |
---|
| 103 | * Check if the request was triggered by an Ajax call. |
---|
| 104 | * @param request the request |
---|
| 105 | * @return <code>true</code> if Ajax |
---|
| 106 | */ |
---|
| 107 | boolean isAjax(request) { |
---|
| 108 | |
---|
| 109 | // look for an ajax=true parameter |
---|
| 110 | if ('true' == request.getParameter('ajax')) { |
---|
| 111 | return true |
---|
| 112 | } |
---|
| 113 | |
---|
| 114 | // check the current request's headers |
---|
| 115 | String ajaxHeader = getSecurityConfig().security.ajaxHeader |
---|
| 116 | if (request.getHeader(ajaxHeader) != null) { |
---|
| 117 | return true |
---|
| 118 | } |
---|
| 119 | |
---|
| 120 | // check the SavedRequest's headers |
---|
| 121 | def savedRequest = request.session.getAttribute(APF.SPRING_SECURITY_SAVED_REQUEST_KEY) |
---|
| 122 | if (savedRequest) { |
---|
| 123 | return savedRequest.getHeaderValues(ajaxHeader).hasNext() |
---|
| 124 | } |
---|
| 125 | |
---|
| 126 | return false |
---|
| 127 | } |
---|
| 128 | |
---|
| 129 | /** |
---|
| 130 | * Quick check to see if the current user is logged in. |
---|
| 131 | * @return <code>true</code> if the principal is a {@link UserDetails} or subclass |
---|
| 132 | */ |
---|
| 133 | boolean isLoggedIn() { |
---|
| 134 | return principal() instanceof UserDetails |
---|
| 135 | } |
---|
| 136 | |
---|
| 137 | /** |
---|
| 138 | * Call when editing, creating, or deleting a Requestmap to flush the cached |
---|
| 139 | * configuration and rebuild using the most recent data. |
---|
| 140 | */ |
---|
| 141 | void clearCachedRequestmaps() { |
---|
| 142 | objectDefinitionSource.reset() |
---|
| 143 | } |
---|
| 144 | |
---|
| 145 | /** |
---|
| 146 | * Delete a role, and if Requestmap class is used to store roles, remove the role |
---|
| 147 | * from all Requestmap definitions. If a Requestmap's config attribute is this role, |
---|
| 148 | * it will be deleted. |
---|
| 149 | * |
---|
| 150 | * @param role the role to delete |
---|
| 151 | */ |
---|
| 152 | void deleteRole(role) { |
---|
| 153 | def conf = getSecurityConfig().security |
---|
| 154 | String configAttributeName = conf.requestMapConfigAttributeField |
---|
| 155 | |
---|
| 156 | role.getClass().withTransaction { status -> |
---|
| 157 | if (conf.useRequestMapDomainClass) { |
---|
| 158 | String roleName = role.authority |
---|
| 159 | def requestmaps = findRequestmapsByRole(roleName, role.getClass(), conf) |
---|
| 160 | requestmaps.each { rm -> |
---|
| 161 | String configAttribute = rm."$configAttributeName" |
---|
| 162 | if (configAttribute.equals(roleName)) { |
---|
| 163 | rm.delete() |
---|
| 164 | } |
---|
| 165 | else { |
---|
| 166 | List parts = configAttribute.split(',') as List |
---|
| 167 | parts.remove roleName |
---|
| 168 | rm."$configAttributeName" = parts.join(',') |
---|
| 169 | } |
---|
| 170 | } |
---|
| 171 | clearCachedRequestmaps() |
---|
| 172 | } |
---|
| 173 | |
---|
| 174 | role.delete() |
---|
| 175 | } |
---|
| 176 | } |
---|
| 177 | |
---|
| 178 | /** |
---|
| 179 | * Update a role, and if Requestmap class is used to store roles, replace the new role |
---|
| 180 | * name in all Requestmap definitions that use it if the name was changed. |
---|
| 181 | * |
---|
| 182 | * @param role the role to update |
---|
| 183 | * @param newProperties the new role attributes ('params' from the calling controller) |
---|
| 184 | */ |
---|
| 185 | boolean updateRole(role, newProperties) { |
---|
| 186 | |
---|
| 187 | String oldRoleName = role.authority |
---|
| 188 | role.properties = newProperties |
---|
| 189 | |
---|
| 190 | def conf = getSecurityConfig().security |
---|
| 191 | |
---|
| 192 | String configAttributeName = conf.requestMapConfigAttributeField |
---|
| 193 | if (conf.useRequestMapDomainClass) { |
---|
| 194 | String newRoleName = role.authority |
---|
| 195 | if (newRoleName != oldRoleName) { |
---|
| 196 | def requestmaps = findRequestmapsByRole(oldRoleName, role.getClass(), conf) |
---|
| 197 | requestmaps.each { rm -> |
---|
| 198 | rm."$configAttributeName" = rm."$configAttributeName".replace(oldRoleName, newRoleName) |
---|
| 199 | } |
---|
| 200 | } |
---|
| 201 | clearCachedRequestmaps() |
---|
| 202 | } |
---|
| 203 | |
---|
| 204 | role.save() |
---|
| 205 | return !role.hasErrors() |
---|
| 206 | } |
---|
| 207 | |
---|
| 208 | private List findRequestmapsByRole(String roleName, domainClass, conf) { |
---|
| 209 | String requestmapClassName = conf.requestMapClass |
---|
| 210 | String configAttributeName = conf.requestMapConfigAttributeField |
---|
| 211 | return domainClass.executeQuery( |
---|
| 212 | "SELECT rm FROM $requestmapClassName rm " + |
---|
| 213 | "WHERE rm.$configAttributeName LIKE :roleName", |
---|
| 214 | [roleName: "%$roleName%"]) |
---|
| 215 | } |
---|
| 216 | } |
---|