1 | package dbnp.authentication |
---|
2 | |
---|
3 | import grails.converters.JSON |
---|
4 | |
---|
5 | import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils |
---|
6 | |
---|
7 | import org.springframework.security.authentication.AccountExpiredException |
---|
8 | import org.springframework.security.authentication.CredentialsExpiredException |
---|
9 | import org.springframework.security.authentication.DisabledException |
---|
10 | import org.springframework.security.authentication.LockedException |
---|
11 | import org.springframework.security.core.context.SecurityContextHolder as SCH |
---|
12 | import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter |
---|
13 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter |
---|
14 | import org.codehaus.groovy.grails.commons.ConfigurationHolder |
---|
15 | |
---|
16 | import dbnp.authentication.* |
---|
17 | |
---|
18 | class LoginController { |
---|
19 | /** |
---|
20 | * Dependency injection for the authenticationTrustResolver. |
---|
21 | */ |
---|
22 | def authenticationTrustResolver |
---|
23 | |
---|
24 | /** |
---|
25 | * Dependency injection for the springSecurityService. |
---|
26 | */ |
---|
27 | def springSecurityService |
---|
28 | |
---|
29 | /** |
---|
30 | * Dependency injection for the GSCF authentication service |
---|
31 | */ |
---|
32 | def authenticationService |
---|
33 | |
---|
34 | /** |
---|
35 | * Default action; redirects to 'defaultTargetUrl' if logged in, /login/auth otherwise. |
---|
36 | */ |
---|
37 | def index = { |
---|
38 | if (springSecurityService.isLoggedIn()) { |
---|
39 | redirect uri: SpringSecurityUtils.securityConfig.successHandler.defaultTargetUrl |
---|
40 | } |
---|
41 | else { |
---|
42 | redirect action: auth, params: params |
---|
43 | } |
---|
44 | } |
---|
45 | |
---|
46 | /** |
---|
47 | * Show the login page. |
---|
48 | */ |
---|
49 | def auth = { |
---|
50 | def config = SpringSecurityUtils.securityConfig |
---|
51 | |
---|
52 | if (springSecurityService.isLoggedIn()) { |
---|
53 | if (params.returnURI) { |
---|
54 | // see basefilters |
---|
55 | redirect uri: params.returnURI |
---|
56 | } else { |
---|
57 | redirect uri: config.successHandler.defaultTargetUrl |
---|
58 | } |
---|
59 | return |
---|
60 | } else if (request.getHeaderNames().find{ it.toLowerCase() == 'useShibboleth' }) { |
---|
61 | // authenticated through shibboleth? |
---|
62 | if (request.getHeaderNames().find{ it.toLowerCase() == 'persistent-id'.toLowerCase() }) { |
---|
63 | // get shibboleth data |
---|
64 | def shibPersistentId = request.getHeader("persistent-id") |
---|
65 | def shibUid = request.getHeader("uid") |
---|
66 | def shibEmail = request.getHeader("Shib-InetOrgPerson-mail") |
---|
67 | def shibOrganization = request.getHeader("schacHomeOrganization") |
---|
68 | def shibDisplayName = request.getHeader("displayName") |
---|
69 | |
---|
70 | // does a user exist with this username? |
---|
71 | def user = SecUser.findByUsername(shibPersistentId) |
---|
72 | if (!user) { |
---|
73 | // no, create a new user |
---|
74 | user = new SecUser() |
---|
75 | user.username = shibPersistentId |
---|
76 | user.enabled = true |
---|
77 | user.userConfirmed = true |
---|
78 | user.adminConfirmed = true |
---|
79 | user.accountExpired = false |
---|
80 | user.accountLocked = false |
---|
81 | user.save() |
---|
82 | |
---|
83 | // refresh user |
---|
84 | user.refresh() |
---|
85 | } |
---|
86 | |
---|
87 | // login user |
---|
88 | //user. |
---|
89 | |
---|
90 | } |
---|
91 | } |
---|
92 | |
---|
93 | String view = 'auth' |
---|
94 | String postUrl = "${request.contextPath}${config.apf.filterProcessesUrl}" |
---|
95 | render view: view, model: [postUrl: postUrl, rememberMeParameter: config.rememberMe.parameter] |
---|
96 | } |
---|
97 | |
---|
98 | /** |
---|
99 | * Shows the login page for users from a module |
---|
100 | */ |
---|
101 | def auth_remote = { |
---|
102 | def consumer = params.consumer |
---|
103 | def token = params.token |
---|
104 | |
---|
105 | // Silent means that the user will be sent back, regardless of his login state. He will not |
---|
106 | // be redirected to the login page. |
---|
107 | def silent = params.silent ? Boolean.valueOf( params.silent ) : false; |
---|
108 | |
---|
109 | if (consumer == null || token == null) { |
---|
110 | throw new Exception("Consumer and Token must be given!"); |
---|
111 | } |
---|
112 | |
---|
113 | log.info( "Remote authentication with " + consumer + " and " + token ) |
---|
114 | |
---|
115 | def returnUrl; |
---|
116 | |
---|
117 | // If no returnUrl is given, find the previous one from the session |
---|
118 | if( params.returnUrl ) { |
---|
119 | returnUrl = params.returnUrl; |
---|
120 | session.authRemoteUrl = returnUrl; |
---|
121 | } else if( session.authRemoteUrl ) { |
---|
122 | returnUrl = session.authRemoteUrl; |
---|
123 | } |
---|
124 | |
---|
125 | // If the user is already authenticated with this session_id, redirect |
---|
126 | // him |
---|
127 | if (authenticationService.isRemotelyLoggedIn(consumer, token)) { |
---|
128 | if (returnUrl) { |
---|
129 | redirect url: returnUrl |
---|
130 | } else { |
---|
131 | redirect controller: 'home' |
---|
132 | } |
---|
133 | return; |
---|
134 | } |
---|
135 | |
---|
136 | // If the user is already logged in locally, we log him in and |
---|
137 | // immediately redirect him |
---|
138 | if (authenticationService.isLoggedIn()) { |
---|
139 | authenticationService.logInRemotely(consumer, token, authenticationService.getLoggedInUser()) |
---|
140 | |
---|
141 | if (returnUrl) { |
---|
142 | redirect url: returnUrl |
---|
143 | } else { |
---|
144 | redirect controller: 'home' |
---|
145 | } |
---|
146 | return; |
---|
147 | } |
---|
148 | |
---|
149 | // On silent login, the user should be sent back anyway |
---|
150 | if( silent ) { |
---|
151 | if (returnUrl) { |
---|
152 | redirect url: returnUrl |
---|
153 | } else { |
---|
154 | redirect controller: 'home' |
---|
155 | } |
---|
156 | } |
---|
157 | |
---|
158 | // Otherwise we show the login screen |
---|
159 | def config = SpringSecurityUtils.securityConfig |
---|
160 | String view = 'auth' |
---|
161 | String postUrl = "${request.contextPath}${config.apf.filterProcessesUrl}" |
---|
162 | |
---|
163 | String redirectUrl = g.createLink(controller: 'login', action: 'auth_remote', params: [consumer: params.consumer, token: params.token], absolute: true) |
---|
164 | render view: view, model: [postUrl: postUrl, |
---|
165 | rememberMeParameter: config.rememberMe.parameter, redirectUrl: redirectUrl] |
---|
166 | } |
---|
167 | |
---|
168 | /** |
---|
169 | * Show denied page. |
---|
170 | */ |
---|
171 | def denied = { |
---|
172 | if (springSecurityService.isLoggedIn() && |
---|
173 | authenticationTrustResolver.isRememberMe(SCH.context?.authentication)) { |
---|
174 | // have cookie but the page is guarded with IS_AUTHENTICATED_FULLY |
---|
175 | redirect action: full, params: params |
---|
176 | } |
---|
177 | } |
---|
178 | |
---|
179 | /** |
---|
180 | * Login page for users with a remember-me cookie but accessing a IS_AUTHENTICATED_FULLY page. |
---|
181 | */ |
---|
182 | def full = { |
---|
183 | def config = SpringSecurityUtils.securityConfig |
---|
184 | render view: 'auth', params: params, |
---|
185 | model: [hasCookie: authenticationTrustResolver.isRememberMe(SCH.context?.authentication), |
---|
186 | postUrl: "${request.contextPath}${config.apf.filterProcessesUrl}"] |
---|
187 | } |
---|
188 | |
---|
189 | /** |
---|
190 | * Callback after a failed login. Redirects to the auth page with a warning message. |
---|
191 | */ |
---|
192 | def authfail = { |
---|
193 | def username = session[UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY] |
---|
194 | String msg = '' |
---|
195 | def exception = session[AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY] |
---|
196 | if (exception) { |
---|
197 | if (exception instanceof AccountExpiredException) { |
---|
198 | msg = SpringSecurityUtils.securityConfig.errors.login.expired |
---|
199 | } |
---|
200 | else if (exception instanceof CredentialsExpiredException) { |
---|
201 | msg = SpringSecurityUtils.securityConfig.errors.login.passwordExpired |
---|
202 | } |
---|
203 | else if (exception instanceof DisabledException) { |
---|
204 | msg = SpringSecurityUtils.securityConfig.errors.login.disabled |
---|
205 | } |
---|
206 | else if (exception instanceof LockedException) { |
---|
207 | msg = SpringSecurityUtils.securityConfig.errors.login.locked |
---|
208 | } |
---|
209 | else { |
---|
210 | msg = SpringSecurityUtils.securityConfig.errors.login.fail |
---|
211 | } |
---|
212 | } |
---|
213 | |
---|
214 | if (springSecurityService.isAjax(request)) { |
---|
215 | // set output header to json |
---|
216 | response.contentType = 'application/json' |
---|
217 | |
---|
218 | render([error: msg] as JSON) |
---|
219 | } |
---|
220 | else { |
---|
221 | flash.message = msg |
---|
222 | redirect action: auth, params: params |
---|
223 | } |
---|
224 | } |
---|
225 | |
---|
226 | /** |
---|
227 | * The Ajax success redirect url. |
---|
228 | */ |
---|
229 | def ajaxSuccess = { |
---|
230 | // set output header to json |
---|
231 | response.contentType = 'application/json' |
---|
232 | |
---|
233 | render([success: true, username: springSecurityService.authentication.name] as JSON) |
---|
234 | } |
---|
235 | |
---|
236 | /** |
---|
237 | * The Ajax denied redirect url. |
---|
238 | */ |
---|
239 | def ajaxDenied = { |
---|
240 | // set output header to json |
---|
241 | response.contentType = 'application/json' |
---|
242 | |
---|
243 | render([error: 'access denied'] as JSON) |
---|
244 | } |
---|
245 | } |
---|