1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.shiro.cas;
20
21 import org.apache.shiro.authc.AuthenticationException;
22 import org.apache.shiro.authc.AuthenticationToken;
23 import org.apache.shiro.subject.Subject;
24 import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
25 import org.apache.shiro.web.util.WebUtils;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 import javax.servlet.ServletRequest;
30 import javax.servlet.ServletResponse;
31 import javax.servlet.http.HttpServletRequest;
32 import java.io.IOException;
33
34 /**
35 * This filter validates the CAS service ticket to authenticate the user. It must be configured on the URL recognized
36 * by the CAS server. For example, in {@code shiro.ini}:
37 * <pre>
38 * [main]
39 * casFilter = org.apache.shiro.cas.CasFilter
40 * ...
41 *
42 * [urls]
43 * /shiro-cas = casFilter
44 * ...
45 * </pre>
46 * (example : http://host:port/mycontextpath/shiro-cas)
47 *
48 * @since 1.2
49 */
50 public class CasFilter extends AuthenticatingFilter {
51
52 private static Logger logger = LoggerFactory.getLogger(CasFilter.class);
53
54 // the name of the parameter service ticket in url
55 private static final String TICKET_PARAMETER = "ticket";
56
57 // the url where the application is redirected if the CAS service ticket validation failed (example : /mycontextpatch/cas_error.jsp)
58 private String failureUrl;
59
60 /**
61 * The token created for this authentication is a CasToken containing the CAS service ticket received on the CAS service url (on which
62 * the filter must be configured).
63 *
64 * @param request the incoming request
65 * @param response the outgoing response
66 * @throws Exception if there is an error processing the request.
67 */
68 @Override
69 protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
70 HttpServletRequest httpRequest = (HttpServletRequest) request;
71 String ticket = httpRequest.getParameter(TICKET_PARAMETER);
72 return new CasToken(ticket);
73 }
74
75 /**
76 * Execute login by creating {@link #createToken(javax.servlet.ServletRequest, javax.servlet.ServletResponse) token} and logging subject
77 * with this token.
78 *
79 * @param request the incoming request
80 * @param response the outgoing response
81 * @throws Exception if there is an error processing the request.
82 */
83 @Override
84 protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
85 return executeLogin(request, response);
86 }
87
88 /**
89 * Returns <code>false</code> to always force authentication (user is never considered authenticated by this filter).
90 *
91 * @param request the incoming request
92 * @param response the outgoing response
93 * @param mappedValue the filter-specific config value mapped to this filter in the URL rules mappings.
94 * @return <code>false</code>
95 */
96 @Override
97 protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
98 return false;
99 }
100
101 /**
102 * If login has been successful, redirect user to the original protected url.
103 *
104 * @param token the token representing the current authentication
105 * @param subject the current authenticated subjet
106 * @param request the incoming request
107 * @param response the outgoing response
108 * @throws Exception if there is an error processing the request.
109 */
110 @Override
111 protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,
112 ServletResponse response) throws Exception {
113 issueSuccessRedirect(request, response);
114 return false;
115 }
116
117 /**
118 * If login has failed, redirect user to the CAS error page (no ticket or ticket validation failed) except if the user is already
119 * authenticated, in which case redirect to the default success url.
120 *
121 * @param token the token representing the current authentication
122 * @param ae the current authentication exception
123 * @param request the incoming request
124 * @param response the outgoing response
125 */
126 @Override
127 protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException ae, ServletRequest request,
128 ServletResponse response) {
129 // is user authenticated or in remember me mode ?
130 Subject subject = getSubject(request, response);
131 if (subject.isAuthenticated() || subject.isRemembered()) {
132 try {
133 issueSuccessRedirect(request, response);
134 } catch (Exception e) {
135 logger.error("Cannot redirect to the default success url", e);
136 }
137 } else {
138 try {
139 WebUtils.issueRedirect(request, response, failureUrl);
140 } catch (IOException e) {
141 logger.error("Cannot redirect to failure url : {}", failureUrl, e);
142 }
143 }
144 return false;
145 }
146
147 public void setFailureUrl(String failureUrl) {
148 this.failureUrl = failureUrl;
149 }
150 }