001: /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015: package org.acegisecurity.ui.openid.consumers;
016:
017: import com.janrain.openid.consumer.AuthRequest;
018: import com.janrain.openid.consumer.Consumer;
019: import com.janrain.openid.consumer.ErrorResponse;
020: import com.janrain.openid.consumer.Response;
021: import com.janrain.openid.consumer.StatusCode;
022: import com.janrain.openid.store.OpenIDStore;
023:
024: import org.acegisecurity.providers.openid.OpenIDAuthenticationStatus;
025: import org.acegisecurity.providers.openid.OpenIDAuthenticationToken;
026:
027: import org.acegisecurity.ui.openid.OpenIDConstants;
028: import org.acegisecurity.ui.openid.OpenIDConsumer;
029: import org.acegisecurity.ui.openid.OpenIDConsumerException;
030:
031: import org.springframework.beans.factory.InitializingBean;
032:
033: import org.springframework.util.Assert;
034:
035: import java.io.IOException;
036:
037: import java.util.HashMap;
038: import java.util.Map;
039:
040: import javax.servlet.http.HttpServletRequest;
041: import javax.servlet.http.HttpSession;
042:
043: /**
044: * OpenIDConsumer implementation using the JanRain OpenID library
045: *
046: * @author Robin Bramley, Opsera Ltd
047: * @version $Id:$
048: */
049: public class JanRainOpenIDConsumer implements OpenIDConsumer,
050: InitializingBean {
051: //~ Static fields/initializers =====================================================================================
052:
053: private static final String SAVED_ID_SESSION_KEY = "savedId";
054:
055: //~ Instance fields ================================================================================================
056:
057: private OpenIDStore store;
058: private String returnToUrl = "j_acegi_openid_security_check";
059:
060: //~ Methods ========================================================================================================
061:
062: public void afterPropertiesSet() throws Exception {
063: Assert.notNull(this .store,
064: "An OpenIDStore must be set on the store property");
065: }
066:
067: /* (non-Javadoc)
068: * @see org.acegisecurity.ui.openid.OpenIDConsumer#beginConsumption(java.lang.String)
069: */
070: public String beginConsumption(HttpServletRequest req,
071: String identityUrl, String returnToUrl)
072: throws OpenIDConsumerException {
073: // fetch/create a session Map for the consumer's use
074: HttpSession session = req.getSession();
075: Map sessionMap = (Map) session
076: .getAttribute(OpenIDConstants.OPENID_SESSION_MAP_KEY);
077:
078: if (sessionMap == null) {
079: sessionMap = new HashMap();
080: session.setAttribute(
081: OpenIDConstants.OPENID_SESSION_MAP_KEY, sessionMap);
082: }
083:
084: Consumer openIdConsumer = new Consumer(sessionMap, store);
085:
086: // Create an Authrequest object from the submitted value
087: AuthRequest ar;
088:
089: try {
090: ar = openIdConsumer.begin(identityUrl);
091: } catch (IOException ioe) {
092: req.getSession().setAttribute(SAVED_ID_SESSION_KEY,
093: escapeAttr(identityUrl));
094: throw new OpenIDConsumerException(
095: "Error on begin consumption for " + identityUrl,
096: ioe);
097: }
098:
099: // construct trust root and return to URLs.
100: String port = "";
101:
102: if (req.getServerPort() != 80) {
103: port = ":" + req.getServerPort();
104: }
105:
106: String trustRoot = req.getScheme() + "://"
107: + req.getServerName() + port + "/";
108: String cp = req.getContextPath();
109:
110: if (!cp.equals("")) {
111: cp = cp.substring(1) + "/";
112: }
113:
114: String returnTo = trustRoot + cp + this .returnToUrl;
115:
116: // send the user the redirect url to proceed with OpenID authentication
117: return ar.redirectUrl(trustRoot, returnTo);
118: }
119:
120: /* (non-Javadoc)
121: * @see org.acegisecurity.ui.openid.OpenIDConsumer#endConsumption(javax.servlet.http.HttpServletRequest)
122: */
123: public OpenIDAuthenticationToken endConsumption(
124: HttpServletRequest req) throws OpenIDConsumerException {
125: HttpSession session = req.getSession();
126: Map sessionMap = (Map) session
127: .getAttribute(OpenIDConstants.OPENID_SESSION_MAP_KEY);
128:
129: if (sessionMap == null) {
130: sessionMap = new HashMap();
131: session.setAttribute(
132: OpenIDConstants.OPENID_SESSION_MAP_KEY, sessionMap);
133: }
134:
135: // get a Consumer instance
136: Consumer openIdConsumer = new Consumer(sessionMap, store);
137:
138: // convert the argument map into the form the library uses with a handy
139: // convenience function
140: Map query = Consumer.filterArgs(req.getParameterMap());
141:
142: // Check the arguments to see what the response was.
143: Response response = openIdConsumer.complete(query);
144:
145: String message = "";
146: OpenIDAuthenticationStatus status;
147:
148: StatusCode statusCode = response.getStatus();
149:
150: if (statusCode == StatusCode.CANCELLED) {
151: status = OpenIDAuthenticationStatus.CANCELLED;
152: } else if (statusCode == StatusCode.ERROR) {
153: status = OpenIDAuthenticationStatus.ERROR;
154: message = ((ErrorResponse) response).getMessage();
155: } else if (statusCode == StatusCode.FAILURE) {
156: status = OpenIDAuthenticationStatus.FAILURE;
157: } else if (statusCode == StatusCode.SETUP_NEEDED) {
158: status = OpenIDAuthenticationStatus.SETUP_NEEDED;
159: } else if (statusCode == StatusCode.SUCCESS) {
160: status = OpenIDAuthenticationStatus.SUCCESS;
161: } else {
162: // unknown status code
163: throw new OpenIDConsumerException(
164: "Unknown response status " + statusCode.toString());
165: }
166:
167: return new OpenIDAuthenticationToken(status, response
168: .getIdentityUrl(), message);
169: }
170:
171: /*
172: * This method escapes characters in a string that can cause problems in
173: * HTML
174: */
175: private String escapeAttr(String s) {
176: if (s == null) {
177: return "";
178: }
179:
180: StringBuffer result = new StringBuffer();
181:
182: for (int i = 0; i < s.length(); i++) {
183: char c = s.charAt(i);
184:
185: if (c == '<') {
186: result.append("<");
187: } else if (c == '>') {
188: result.append(">");
189: } else if (c == '&') {
190: result.append("&");
191: } else if (c == '\"') {
192: result.append(""");
193: } else if (c == '\'') {
194: result.append("'");
195: } else if (c == '\\') {
196: result.append("\");
197: } else {
198: result.append(c);
199: }
200: }
201:
202: return result.toString();
203: }
204:
205: public void setReturnToUrl(String returnToUrl) {
206: this .returnToUrl = returnToUrl;
207: }
208:
209: // dependency injection
210: public void setStore(OpenIDStore store) {
211: this.store = store;
212: }
213: }
|