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