diff --git a/pom.xml b/pom.xml
index e131c96cae..16de3ffc22 100644
--- a/pom.xml
+++ b/pom.xml
@@ -199,6 +199,9 @@
Mike Perham
+
+ Robin Bramley
+
diff --git a/sandbox/openid/pom.xml b/sandbox/openid/pom.xml
new file mode 100644
index 0000000000..1edfd3117f
--- /dev/null
+++ b/sandbox/openid/pom.xml
@@ -0,0 +1,83 @@
+
+ 4.0.0
+
+ org.acegisecurity
+ acegi-security-sandbox
+ 1.0.2
+
+ acegi-security-openid
+ Acegi Security System for Spring - OpenID support
+ Acegi Security System for Spring - Support for OpenID
+ 0.1-SNAPSHOT
+
+
+
+ AcegiMaven
+ Acegi 3rd party repository
+ http://acegisecurity.sourceforge.net/maven
+
+ true
+
+
+
+
+
+ scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity/sandbox/openid
+
+
+ scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity/sandbox/openid
+
+ http://svn.sourceforge.net/viewcvs.cgi/acegisecurity/trunk/acegisecurity/sandbox/openid/
+
+
+
+
+ org.springframework
+ spring-mock
+ true
+
+
+ com.janrain
+ Janrain-Openid
+ 20070226
+
+
+ gnu
+ libidn
+ 0.6.3
+
+
+ org.apache.geronimo.specs
+ geronimo-servlet_2.4_spec
+ 1.1.1
+ compile
+ true
+
+
+
+
+
+
+
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/AuthenticationCancelledException.java b/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/AuthenticationCancelledException.java
new file mode 100644
index 0000000000..7f68b5ce92
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/AuthenticationCancelledException.java
@@ -0,0 +1,36 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.providers.openid;
+
+import org.acegisecurity.AuthenticationException;
+
+
+/**
+ * Indicates that OpenID authentication was cancelled
+ *
+ * @author Robin Bramley, Opsera Ltd
+ * @version $Id:$
+ */
+public class AuthenticationCancelledException extends AuthenticationException {
+ //~ Constructors ===================================================================================================
+
+ public AuthenticationCancelledException(String msg) {
+ super(msg);
+ }
+
+ public AuthenticationCancelledException(String msg, Throwable t) {
+ super(msg, t);
+ }
+}
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/OpenIDAuthenticationProvider.java b/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/OpenIDAuthenticationProvider.java
new file mode 100644
index 0000000000..516c9cabf1
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/OpenIDAuthenticationProvider.java
@@ -0,0 +1,108 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.providers.openid;
+
+import org.acegisecurity.Authentication;
+import org.acegisecurity.AuthenticationException;
+import org.acegisecurity.AuthenticationServiceException;
+import org.acegisecurity.BadCredentialsException;
+
+import org.acegisecurity.providers.AuthenticationProvider;
+import org.acegisecurity.providers.cas.CasAuthoritiesPopulator;
+
+import org.acegisecurity.userdetails.UserDetails;
+
+import org.springframework.beans.factory.InitializingBean;
+
+import org.springframework.util.Assert;
+
+
+/**
+ * Finalises the OpenID authentication by obtaining local roles
+ *
+ * @author Robin Bramley, Opsera Ltd.
+ */
+public class OpenIDAuthenticationProvider implements AuthenticationProvider, InitializingBean {
+ //~ Instance fields ================================================================================================
+
+ private CasAuthoritiesPopulator ssoAuthoritiesPopulator;
+
+ //~ Methods ========================================================================================================
+
+ public void afterPropertiesSet() throws Exception {
+ Assert.notNull(this.ssoAuthoritiesPopulator, "The ssoAuthoritiesPopulator must be set");
+ }
+
+ /* (non-Javadoc)
+ * @see org.acegisecurity.providers.AuthenticationProvider#authenticate(org.acegisecurity.Authentication)
+ */
+ public Authentication authenticate(Authentication authentication)
+ throws AuthenticationException {
+ if (!supports(authentication.getClass())) {
+ return null;
+ }
+
+ if (authentication instanceof OpenIDAuthenticationToken) {
+ OpenIDAuthenticationToken response = (OpenIDAuthenticationToken) authentication;
+ OpenIDAuthenticationStatus status = response.getStatus();
+
+ // handle the various possibilites
+ if (status == OpenIDAuthenticationStatus.SUCCESS) {
+ //String message = "Log in succeeded: ";// + savedId;
+
+ /* TODO: allow for regex for mapping URL
+ * e.g. http://mydomain.com/username
+ * or http://{username}.mydomain.com
+ */
+
+ // Lookup user details
+ UserDetails userDetails = this.ssoAuthoritiesPopulator.getUserDetails(response.getIdentityUrl());
+
+ authentication = new OpenIDAuthenticationToken(userDetails.getAuthorities(), response.getStatus(),
+ response.getIdentityUrl());
+
+ return authentication;
+ } else if (status == OpenIDAuthenticationStatus.CANCELLED) {
+ throw new AuthenticationCancelledException("Log in cancelled");
+ } else if (status == OpenIDAuthenticationStatus.ERROR) {
+ throw new AuthenticationServiceException("Error message from server: " + response.getMessage());
+ } else if (status == OpenIDAuthenticationStatus.FAILURE) {
+ throw new BadCredentialsException("Log in failed - identity could not be verified");
+ } else if (status == OpenIDAuthenticationStatus.SETUP_NEEDED) {
+ throw new AuthenticationServiceException(
+ "The server responded setup was needed, which shouldn't happen");
+ } else {
+ throw new AuthenticationServiceException("Unrecognized return value " + status.toString());
+ }
+ }
+
+ return null;
+ }
+
+ public void setSsoAuthoritiesPopulator(CasAuthoritiesPopulator ssoAuthoritiesPopulator) {
+ this.ssoAuthoritiesPopulator = ssoAuthoritiesPopulator;
+ }
+
+ /* (non-Javadoc)
+ * @see org.acegisecurity.providers.AuthenticationProvider#supports(java.lang.Class)
+ */
+ public boolean supports(Class authentication) {
+ if (OpenIDAuthenticationToken.class.isAssignableFrom(authentication)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/OpenIDAuthenticationStatus.java b/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/OpenIDAuthenticationStatus.java
new file mode 100644
index 0000000000..1ad165d7ce
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/OpenIDAuthenticationStatus.java
@@ -0,0 +1,69 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.providers.openid;
+
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+
+
+/**
+ * Based on JanRain status codes
+ *
+ * @author JanRain Inc.
+ * @author Robin Bramley, Opsera Ltd
+ */
+public class OpenIDAuthenticationStatus implements Serializable {
+ //~ Static fields/initializers =====================================================================================
+
+ private static final long serialVersionUID = -998877665544332211L;
+ private static int nextOrdinal = 0;
+
+ /** This code indicates a successful authentication request */
+ public static final OpenIDAuthenticationStatus SUCCESS = new OpenIDAuthenticationStatus("success");
+
+ /** This code indicates a failed authentication request */
+ public static final OpenIDAuthenticationStatus FAILURE = new OpenIDAuthenticationStatus("failure");
+
+ /** This code indicates the server reported an error */
+ public static final OpenIDAuthenticationStatus ERROR = new OpenIDAuthenticationStatus("error");
+
+ /** This code indicates that the user needs to do additional work to prove their identity */
+ public static final OpenIDAuthenticationStatus SETUP_NEEDED = new OpenIDAuthenticationStatus("setup needed");
+
+ /** This code indicates that the user cancelled their login request */
+ public static final OpenIDAuthenticationStatus CANCELLED = new OpenIDAuthenticationStatus("cancelled");
+ private static final OpenIDAuthenticationStatus[] PRIVATE_VALUES = {SUCCESS, FAILURE, ERROR, SETUP_NEEDED, CANCELLED};
+
+ //~ Instance fields ================================================================================================
+
+ private String name;
+ private final int ordinal = nextOrdinal++;
+
+ //~ Constructors ===================================================================================================
+
+ private OpenIDAuthenticationStatus(String name) {
+ this.name = name;
+ }
+
+ //~ Methods ========================================================================================================
+
+ private Object readResolve() throws ObjectStreamException {
+ return PRIVATE_VALUES[ordinal];
+ }
+
+ public String toString() {
+ return name;
+ }
+}
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/OpenIDAuthenticationToken.java b/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/OpenIDAuthenticationToken.java
new file mode 100644
index 0000000000..75288b020f
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/OpenIDAuthenticationToken.java
@@ -0,0 +1,88 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.providers.openid;
+
+import org.acegisecurity.GrantedAuthority;
+
+import org.acegisecurity.providers.AbstractAuthenticationToken;
+
+
+/**
+ * OpenID Authentication Token
+ *
+ * @author Robin Bramley, Opsera Ltd
+ */
+public class OpenIDAuthenticationToken extends AbstractAuthenticationToken {
+ //~ Instance fields ================================================================================================
+
+ private OpenIDAuthenticationStatus status;
+ private String identityUrl;
+ private String message;
+
+ //~ Constructors ===================================================================================================
+
+ public OpenIDAuthenticationToken(OpenIDAuthenticationStatus status, String identityUrl, String message) {
+ super(new GrantedAuthority[0]);
+ this.status = status;
+ this.identityUrl = identityUrl;
+ this.message = message;
+ setAuthenticated(false);
+ }
+
+/**
+ * Created by the OpenIDAuthenticationProvider on successful authentication.
+ * Do not use directly
+ *
+ * @param authorities
+ * @param status
+ * @param identityUrl
+ */
+ public OpenIDAuthenticationToken(GrantedAuthority[] authorities, OpenIDAuthenticationStatus status,
+ String identityUrl) {
+ super(authorities);
+ this.status = status;
+ this.identityUrl = identityUrl;
+
+ setAuthenticated(true);
+ }
+
+ //~ Methods ========================================================================================================
+
+ /* (non-Javadoc)
+ * @see org.acegisecurity.Authentication#getCredentials()
+ */
+ public Object getCredentials() {
+ return null;
+ }
+
+ public String getIdentityUrl() {
+ return identityUrl;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ /* (non-Javadoc)
+ * @see org.acegisecurity.Authentication#getPrincipal()
+ */
+ public Object getPrincipal() {
+ return identityUrl;
+ }
+
+ public OpenIDAuthenticationStatus getStatus() {
+ return status;
+ }
+}
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/package.html b/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/package.html
new file mode 100644
index 0000000000..5fc7ffefe9
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/providers/openid/package.html
@@ -0,0 +1,6 @@
+
+
+An authentication provider that can process OpenID
+Authentication Tokens as created by implementations of the OpenIDConsumer interface.
+
+
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDConstants.java b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDConstants.java
new file mode 100644
index 0000000000..10920d1728
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDConstants.java
@@ -0,0 +1,26 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.ui.openid;
+
+/**
+ * Constants required by OpenID classes
+ *
+ * @author Robin Bramley, Opsera Ltd
+ */
+public class OpenIDConstants {
+ //~ Static fields/initializers =====================================================================================
+
+ public static final String OPENID_SESSION_MAP_KEY = "openid.session";
+}
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDConsumer.java b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDConsumer.java
new file mode 100644
index 0000000000..a28b2d7674
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDConsumer.java
@@ -0,0 +1,62 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.ui.openid;
+
+import org.acegisecurity.providers.openid.OpenIDAuthenticationToken;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * An interface for OpenID library implementations
+ *
+ * @author Robin Bramley, Opsera Ltd
+ *
+ */
+public interface OpenIDConsumer {
+ //~ Methods ========================================================================================================
+
+ /**
+ * Start the authentication process
+ *
+ * @param req
+ * @param identityUrl
+ *
+ * @return redirection URL
+ *
+ * @throws OpenIDConsumerException
+ */
+ public String beginConsumption(HttpServletRequest req, String identityUrl)
+ throws OpenIDConsumerException;
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param req
+ *
+ * @return
+ *
+ * @throws OpenIDConsumerException
+ */
+ public OpenIDAuthenticationToken endConsumption(HttpServletRequest req)
+ throws OpenIDConsumerException;
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param returnToUrl
+ */
+ public void setReturnToUrl(String returnToUrl);
+}
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDConsumerException.java b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDConsumerException.java
new file mode 100644
index 0000000000..8957dee802
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDConsumerException.java
@@ -0,0 +1,32 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.ui.openid;
+
+/**
+ * Thrown by an OpenIDConsumer if it cannot process a request
+ *
+ * @author Robin Bramley, Opsera Ltd
+ */
+public class OpenIDConsumerException extends Exception {
+ //~ Constructors ===================================================================================================
+
+ public OpenIDConsumerException(String message) {
+ super(message);
+ }
+
+ public OpenIDConsumerException(String message, Throwable t) {
+ super(message, t);
+ }
+}
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDLoginInitiationServlet.java b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDLoginInitiationServlet.java
new file mode 100644
index 0000000000..eacf237e4c
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDLoginInitiationServlet.java
@@ -0,0 +1,180 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.ui.openid;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.util.StringUtils;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+
+/**
+ * This servlet starts the OpenID authentication process.
+ *
+ *
Sample web.xml configuration:
+ *
+ *
<servlet>
+ *
<servlet-name>openid</servlet-name>
+ *
<servlet-class>org.acegisecurity.ui.openid.OpenIDLoginInitiationServlet</servlet-class>
+ *
<load-on-startup>1</load-on-startup>
+ *
<init-param>
+ *
<description>The error page - will receive error "message"</description>
+ *
<param-name>errorPage</param-name>
+ *
<param-value>index.jsp</param-value>
+ *
</init-param>
+ *
</servlet>
+ *
<servlet-mapping>
+ *
<servlet-name>openid</servlet-name>
+ *
<url-pattern>/j_acegi_openid_start</url-pattern>
+ *
</servlet-mapping>
+ *
+ *
Sample login form:
+ *
<form method="POST" action="j_acegi_openid_start">
+ *
<input type="text" name="j_username" />
+ *
<input type="password" name="j_password" />
+ *
<input type="submit" value="Verify" />
+ *
</form>
+ *
+ *
Usage notes:
+ * Requires an openIDConsumer Spring bean implementing the {@link OpenIDConsumer} interface
+ * It will pass off to standard form-based authentication if appropriate
+ * (note that AuthenticationProcessingFilter requires j_username, j_password)
+ *
+ *
Outstanding items:
+ * TODO: config flag for whether OpenID only or dual mode?
+ * TODO: username matching logic
+ *
+ * @author Robin Bramley, Opsera Ltd
+ * @version $Id:$
+ */
+public class OpenIDLoginInitiationServlet extends HttpServlet {
+ final static long serialVersionUID = -997766L;
+ private static final Log logger = LogFactory.getLog(OpenIDLoginInitiationServlet.class);
+ private static final String passwordField = "j_password";
+
+ /**
+ * Servlet config key for looking up the the HttpServletRequest parameter name
+ * containing the OpenID Identity URL from the Servlet config.
+ *
Only set the identityField servlet init-param if you are not using j_username
+ *
+ *
<init-param>
+ *
<description>The identity form field parameter</description>
+ *
<param-name>identityField</param-name>
+ *
<param-value>/openid_url</param-value>
+ *
</init-param>
+ */
+ public static final String IDENTITY_FIELD_KEY = "identityField";
+
+ /**
+ * Servlet config key for the return to URL
+ */
+ public static final String ERROR_PAGE_KEY = "errorPage";
+
+ /**
+ * Servlet config key for looking up the form login URL from the Servlet config.
+ *
Only set the formLogin servlet init-param if you are not using /j_acegi_security_check
+ *
+ *
<init-param>
+ *
<description>The form login URL - for standard authentication</description>
+ *
<param-name>formLogin</param-name>
+ *
<param-value>/custom_acegi_security_check</param-value>
+ *
</init-param>
+ */
+ public static final String FORM_LOGIN_URL_KEY = "formLogin";
+
+ /**
+ * Spring context key for the OpenID consumer bean
+ */
+ public static final String CONSUMER_KEY = "openIDConsumer";
+ private String errorPage = "index.jsp";
+ private String identityField = "j_username";
+ private String formLoginUrl = "/j_acegi_security_check";
+
+ /**
+ * Check for init-params
+ *
+ * @Override
+ */
+ public void init() throws ServletException {
+ super.init();
+
+ String configErrorPage = getServletConfig()
+ .getInitParameter(ERROR_PAGE_KEY);
+
+ if (StringUtils.hasText(configErrorPage)) {
+ errorPage = configErrorPage;
+ }
+
+ String configIdentityField = getServletConfig()
+ .getInitParameter(IDENTITY_FIELD_KEY);
+
+ if (StringUtils.hasText(configIdentityField)) {
+ identityField = configIdentityField;
+ }
+
+ String configFormLoginUrl = getServletConfig()
+ .getInitParameter(FORM_LOGIN_URL_KEY);
+
+ if (StringUtils.hasText(configFormLoginUrl)) {
+ formLoginUrl = configFormLoginUrl;
+ }
+ }
+
+ /**
+ * Process the form post - all the work is done by the OpenIDConsumer.beginConsumption method
+ *
+ * @Override
+ */
+ protected void doPost(HttpServletRequest req, HttpServletResponse res)
+ throws ServletException, IOException {
+ WebApplicationContext webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
+ OpenIDConsumer consumer = (OpenIDConsumer) webApplicationContext.getBean(CONSUMER_KEY);
+
+ // get the submitted id field
+ String id = req.getParameter(identityField);
+
+ // assume page will validate?
+ //TODO: null checking!
+
+ //TODO: pattern matching
+ String password = req.getParameter(passwordField);
+
+ if ((password != null) && (password.length() > 0)) {
+ logger.debug("Attempting to authenticate using username/password");
+
+ // forward to authenticationProcessingFilter (/j_acegi_security_check - depends on param names)
+ req.getRequestDispatcher(formLoginUrl).forward(req, res);
+
+ } else {
+ // send the user the redirect url to proceed with OpenID authentication
+ try {
+ String redirect = consumer.beginConsumption(req, id);
+ logger.debug("Redirecting to: " + redirect);
+ res.sendRedirect(redirect);
+ } catch (OpenIDConsumerException oice) {
+ logger.error("Consumer error!", oice);
+ req.setAttribute("message", oice.getMessage());
+ req.getRequestDispatcher(errorPage).forward(req, res);
+ }
+ }
+ }
+}
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDResponseProcessingFilter.java b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDResponseProcessingFilter.java
new file mode 100644
index 0000000000..9b369201fc
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/OpenIDResponseProcessingFilter.java
@@ -0,0 +1,84 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.ui.openid;
+
+import org.acegisecurity.Authentication;
+import org.acegisecurity.AuthenticationException;
+import org.acegisecurity.AuthenticationServiceException;
+
+import org.acegisecurity.providers.openid.OpenIDAuthenticationToken;
+
+import org.acegisecurity.ui.AbstractProcessingFilter;
+import org.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * Process the response from the OpenID server to the returnTo URL.
+ *
+ * @author Robin Bramley, Opsera Ltd
+ * @version $Id:$
+ */
+public class OpenIDResponseProcessingFilter extends AbstractProcessingFilter {
+ //~ Instance fields ================================================================================================
+
+ private OpenIDConsumer consumer;
+
+ //~ Methods ========================================================================================================
+
+ /* (non-Javadoc)
+ * @see org.acegisecurity.ui.AbstractProcessingFilter#attemptAuthentication(javax.servlet.http.HttpServletRequest)
+ * @Override
+ */
+ public Authentication attemptAuthentication(HttpServletRequest req)
+ throws AuthenticationException {
+ OpenIDAuthenticationToken token;
+
+ try {
+ token = consumer.endConsumption(req);
+ } catch (OpenIDConsumerException oice) {
+ throw new AuthenticationServiceException("Consumer error", oice);
+ }
+
+ // delegate to the auth provider
+ Authentication authentication = this.getAuthenticationManager().authenticate(token);
+
+ if (authentication.isAuthenticated()) {
+ req.getSession()
+ .setAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY, token.getIdentityUrl());
+ }
+
+ return authentication;
+ }
+
+ /* (non-Javadoc)
+ * @see org.acegisecurity.ui.AbstractProcessingFilter#getDefaultFilterProcessesUrl()
+ * @Override
+ */
+ public String getDefaultFilterProcessesUrl() {
+ return "/j_acegi_openid_security_check";
+ }
+
+ // dependency injection
+ /**
+ * DOCUMENT ME!
+ *
+ * @param consumer The OpenIDConsumer to set.
+ */
+ public void setConsumer(OpenIDConsumer consumer) {
+ this.consumer = consumer;
+ }
+}
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/consumers/JanRainOpenIDConsumer.java b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/consumers/JanRainOpenIDConsumer.java
new file mode 100644
index 0000000000..b275ab0095
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/consumers/JanRainOpenIDConsumer.java
@@ -0,0 +1,201 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.ui.openid.consumers;
+
+import com.janrain.openid.consumer.AuthRequest;
+import com.janrain.openid.consumer.Consumer;
+import com.janrain.openid.consumer.ErrorResponse;
+import com.janrain.openid.consumer.Response;
+import com.janrain.openid.consumer.StatusCode;
+import com.janrain.openid.store.OpenIDStore;
+
+import org.acegisecurity.providers.openid.OpenIDAuthenticationStatus;
+import org.acegisecurity.providers.openid.OpenIDAuthenticationToken;
+
+import org.acegisecurity.ui.openid.OpenIDConstants;
+import org.acegisecurity.ui.openid.OpenIDConsumer;
+import org.acegisecurity.ui.openid.OpenIDConsumerException;
+
+import org.springframework.beans.factory.InitializingBean;
+
+import org.springframework.util.Assert;
+
+import java.io.IOException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+
+/**
+ * OpenIDConsumer implementation using the JanRain OpenID library
+ *
+ * @author Robin Bramley, Opsera Ltd
+ * @version $Id:$
+ */
+public class JanRainOpenIDConsumer implements OpenIDConsumer, InitializingBean {
+ //~ Static fields/initializers =====================================================================================
+
+ private static final String SAVED_ID_SESSION_KEY = "savedId";
+
+ //~ Instance fields ================================================================================================
+
+ private OpenIDStore store;
+ private String returnToUrl = "j_acegi_openid_security_check";
+
+ //~ Methods ========================================================================================================
+
+ public void afterPropertiesSet() throws Exception {
+ Assert.notNull(this.store, "An OpenIDStore must be set on the store property");
+ }
+
+ /* (non-Javadoc)
+ * @see org.acegisecurity.ui.openid.OpenIDConsumer#beginConsumption(java.lang.String)
+ */
+ public String beginConsumption(HttpServletRequest req, String identityUrl)
+ throws OpenIDConsumerException {
+ // fetch/create a session Map for the consumer's use
+ HttpSession session = req.getSession();
+ Map sessionMap = (Map) session.getAttribute(OpenIDConstants.OPENID_SESSION_MAP_KEY);
+
+ if (sessionMap == null) {
+ sessionMap = new HashMap();
+ session.setAttribute(OpenIDConstants.OPENID_SESSION_MAP_KEY, sessionMap);
+ }
+
+ Consumer openIdConsumer = new Consumer(sessionMap, store);
+
+ // Create an Authrequest object from the submitted value
+ AuthRequest ar;
+
+ try {
+ ar = openIdConsumer.begin(identityUrl);
+ } catch (IOException ioe) {
+ req.getSession().setAttribute(SAVED_ID_SESSION_KEY, escapeAttr(identityUrl));
+ throw new OpenIDConsumerException("Error on begin consumption for " + identityUrl, ioe);
+ }
+
+ // construct trust root and return to URLs.
+ String port = "";
+
+ if (req.getServerPort() != 80) {
+ port = ":" + req.getServerPort();
+ }
+
+ String trustRoot = req.getScheme() + "://" + req.getServerName() + port + "/";
+ String cp = req.getContextPath();
+
+ if (!cp.equals("")) {
+ cp = cp.substring(1) + "/";
+ }
+
+ String returnTo = trustRoot + cp + returnToUrl;
+
+ // send the user the redirect url to proceed with OpenID authentication
+ return ar.redirectUrl(trustRoot, returnTo);
+ }
+
+ /* (non-Javadoc)
+ * @see org.acegisecurity.ui.openid.OpenIDConsumer#endConsumption(javax.servlet.http.HttpServletRequest)
+ */
+ public OpenIDAuthenticationToken endConsumption(HttpServletRequest req)
+ throws OpenIDConsumerException {
+ HttpSession session = req.getSession();
+ Map sessionMap = (Map) session.getAttribute(OpenIDConstants.OPENID_SESSION_MAP_KEY);
+
+ if (sessionMap == null) {
+ sessionMap = new HashMap();
+ session.setAttribute(OpenIDConstants.OPENID_SESSION_MAP_KEY, sessionMap);
+ }
+
+ // get a Consumer instance
+ Consumer openIdConsumer = new Consumer(sessionMap, store);
+
+ // convert the argument map into the form the library uses with a handy
+ // convenience function
+ Map query = Consumer.filterArgs(req.getParameterMap());
+
+ // Check the arguments to see what the response was.
+ Response response = openIdConsumer.complete(query);
+
+ String message = "";
+ OpenIDAuthenticationStatus status;
+
+ StatusCode statusCode = response.getStatus();
+
+ if (statusCode == StatusCode.CANCELLED) {
+ status = OpenIDAuthenticationStatus.CANCELLED;
+ } else if (statusCode == StatusCode.ERROR) {
+ status = OpenIDAuthenticationStatus.ERROR;
+ message = ((ErrorResponse) response).getMessage();
+ } else if (statusCode == StatusCode.FAILURE) {
+ status = OpenIDAuthenticationStatus.FAILURE;
+ } else if (statusCode == StatusCode.SETUP_NEEDED) {
+ status = OpenIDAuthenticationStatus.SETUP_NEEDED;
+ } else if (statusCode == StatusCode.SUCCESS) {
+ status = OpenIDAuthenticationStatus.SUCCESS;
+ } else {
+ // unknown status code
+ throw new OpenIDConsumerException("Unknown response status " + statusCode.toString());
+ }
+
+ return new OpenIDAuthenticationToken(status, response.getIdentityUrl(), message);
+ }
+
+ /*
+ * This method escapes characters in a string that can cause problems in
+ * HTML
+ */
+ private String escapeAttr(String s) {
+ if (s == null) {
+ return "";
+ }
+
+ StringBuffer result = new StringBuffer();
+
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+
+ if (c == '<') {
+ result.append("<");
+ } else if (c == '>') {
+ result.append(">");
+ } else if (c == '&') {
+ result.append("&");
+ } else if (c == '\"') {
+ result.append(""");
+ } else if (c == '\'') {
+ result.append("'");
+ } else if (c == '\\') {
+ result.append("\");
+ } else {
+ result.append(c);
+ }
+ }
+
+ return result.toString();
+ }
+
+ public void setReturnToUrl(String returnToUrl) {
+ this.returnToUrl = returnToUrl;
+ }
+
+ // dependency injection
+ public void setStore(OpenIDStore store) {
+ this.store = store;
+ }
+}
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/consumers/package.html b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/consumers/package.html
new file mode 100644
index 0000000000..913d6930e9
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/consumers/package.html
@@ -0,0 +1,5 @@
+
+
+Implementations of the OpenIDConsumer interface using 3rd party libraries.
+
+
diff --git a/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/package.html b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/package.html
new file mode 100644
index 0000000000..aa8555d718
--- /dev/null
+++ b/sandbox/openid/src/main/java/org/acegisecurity/ui/openid/package.html
@@ -0,0 +1,5 @@
+
+
+Authenticates standard web browser users via OpenID.
+
+
\ No newline at end of file
diff --git a/sandbox/openid/src/test/java/org/acegisecurity/providers/openid/MockAuthoritiesPopulator.java b/sandbox/openid/src/test/java/org/acegisecurity/providers/openid/MockAuthoritiesPopulator.java
new file mode 100644
index 0000000000..5760e978c2
--- /dev/null
+++ b/sandbox/openid/src/test/java/org/acegisecurity/providers/openid/MockAuthoritiesPopulator.java
@@ -0,0 +1,40 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.providers.openid;
+
+import org.acegisecurity.AuthenticationException;
+import org.acegisecurity.GrantedAuthority;
+import org.acegisecurity.GrantedAuthorityImpl;
+
+import org.acegisecurity.providers.cas.CasAuthoritiesPopulator;
+
+import org.acegisecurity.userdetails.User;
+import org.acegisecurity.userdetails.UserDetails;
+
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author Robin Bramley, Opsera Ltd
+ */
+public class MockAuthoritiesPopulator implements CasAuthoritiesPopulator {
+ //~ Methods ========================================================================================================
+
+ public UserDetails getUserDetails(String ssoUserId)
+ throws AuthenticationException {
+ return new User(ssoUserId, "password", true, true, true, true,
+ new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl("ROLE_B")});
+ }
+}
diff --git a/sandbox/openid/src/test/java/org/acegisecurity/providers/openid/OpenIDAuthenticationProviderTests.java b/sandbox/openid/src/test/java/org/acegisecurity/providers/openid/OpenIDAuthenticationProviderTests.java
new file mode 100644
index 0000000000..4d77d76103
--- /dev/null
+++ b/sandbox/openid/src/test/java/org/acegisecurity/providers/openid/OpenIDAuthenticationProviderTests.java
@@ -0,0 +1,194 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.providers.openid;
+
+import junit.framework.TestCase;
+
+import org.acegisecurity.Authentication;
+import org.acegisecurity.AuthenticationServiceException;
+import org.acegisecurity.BadCredentialsException;
+
+import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+
+
+/**
+ * Tests {@link OpenIDAuthenticationProvider}
+ *
+ * @author Robin Bramley, Opsera Ltd
+ */
+public class OpenIDAuthenticationProviderTests extends TestCase {
+ //~ Static fields/initializers =====================================================================================
+
+ private static final String USERNAME = "user.acegiopenid.com";
+
+ //~ Methods ========================================================================================================
+
+ /*
+ * Test method for 'org.acegisecurity.providers.openid.OpenIDAuthenticationProvider.authenticate(Authentication)'
+ */
+ public void testAuthenticateCancel() {
+ OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
+ provider.setSsoAuthoritiesPopulator(new MockAuthoritiesPopulator());
+
+ Authentication preAuth = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.CANCELLED, USERNAME, "");
+
+ assertFalse(preAuth.isAuthenticated());
+
+ try {
+ provider.authenticate(preAuth);
+ fail("Should throw an AuthenticationException");
+ } catch (AuthenticationCancelledException expected) {
+ assertEquals("Log in cancelled", expected.getMessage());
+ }
+ }
+
+ /*
+ * Test method for 'org.acegisecurity.providers.openid.OpenIDAuthenticationProvider.authenticate(Authentication)'
+ */
+ public void testAuthenticateError() {
+ OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
+ provider.setSsoAuthoritiesPopulator(new MockAuthoritiesPopulator());
+
+ Authentication preAuth = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.ERROR, USERNAME, "");
+
+ assertFalse(preAuth.isAuthenticated());
+
+ try {
+ provider.authenticate(preAuth);
+ fail("Should throw an AuthenticationException");
+ } catch (AuthenticationServiceException expected) {
+ assertEquals("Error message from server: ", expected.getMessage());
+ }
+ }
+
+ /*
+ * Test method for 'org.acegisecurity.providers.openid.OpenIDAuthenticationProvider.authenticate(Authentication)'
+ */
+ public void testAuthenticateFailure() {
+ OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
+ provider.setSsoAuthoritiesPopulator(new MockAuthoritiesPopulator());
+
+ Authentication preAuth = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.FAILURE, USERNAME, "");
+
+ assertFalse(preAuth.isAuthenticated());
+
+ try {
+ provider.authenticate(preAuth);
+ fail("Should throw an AuthenticationException");
+ } catch (BadCredentialsException expected) {
+ assertEquals("Log in failed - identity could not be verified", expected.getMessage());
+ }
+ }
+
+ /*
+ * Test method for 'org.acegisecurity.providers.openid.OpenIDAuthenticationProvider.authenticate(Authentication)'
+ */
+ public void testAuthenticateSetupNeeded() {
+ OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
+ provider.setSsoAuthoritiesPopulator(new MockAuthoritiesPopulator());
+
+ Authentication preAuth = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SETUP_NEEDED, USERNAME, "");
+
+ assertFalse(preAuth.isAuthenticated());
+
+ try {
+ provider.authenticate(preAuth);
+ fail("Should throw an AuthenticationException");
+ } catch (AuthenticationServiceException expected) {
+ assertEquals("The server responded setup was needed, which shouldn't happen", expected.getMessage());
+ }
+ }
+
+ /*
+ * Test method for 'org.acegisecurity.providers.openid.OpenIDAuthenticationProvider.authenticate(Authentication)'
+ */
+ public void testAuthenticateSuccess() {
+ OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
+ provider.setSsoAuthoritiesPopulator(new MockAuthoritiesPopulator());
+
+ Authentication preAuth = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SUCCESS, USERNAME, "");
+
+ assertFalse(preAuth.isAuthenticated());
+
+ Authentication postAuth = provider.authenticate(preAuth);
+
+ assertNotNull(postAuth);
+ assertTrue(postAuth instanceof OpenIDAuthenticationToken);
+ assertTrue(postAuth.isAuthenticated());
+ assertNotNull(postAuth.getPrincipal());
+ assertEquals(preAuth.getPrincipal(), postAuth.getPrincipal());
+ assertNotNull(postAuth.getAuthorities());
+ assertTrue(postAuth.getAuthorities().length > 0);
+ assertTrue(((OpenIDAuthenticationToken) postAuth).getStatus() == OpenIDAuthenticationStatus.SUCCESS);
+ assertTrue(((OpenIDAuthenticationToken) postAuth).getMessage() == null);
+ }
+
+ public void testDetectsMissingAuthoritiesPopulator() {
+ OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
+
+ try {
+ provider.afterPropertiesSet();
+ fail("Should have thrown Exception");
+ } catch (Exception expected) {
+ assertEquals("The ssoAuthoritiesPopulator must be set", expected.getMessage());
+ }
+ }
+
+ /*
+ * Test method for 'org.acegisecurity.providers.openid.OpenIDAuthenticationProvider.supports(Class)'
+ */
+ public void testDoesntSupport() {
+ OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
+ provider.setSsoAuthoritiesPopulator(new MockAuthoritiesPopulator());
+
+ assertFalse(provider.supports(UsernamePasswordAuthenticationToken.class));
+ }
+
+ /*
+ * Test method for 'org.acegisecurity.providers.openid.OpenIDAuthenticationProvider.authenticate(Authentication)'
+ */
+ public void testIgnoresUserPassAuthToken() {
+ OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
+ provider.setSsoAuthoritiesPopulator(new MockAuthoritiesPopulator());
+
+ UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(USERNAME, "password");
+ assertEquals(null, provider.authenticate(token));
+ }
+
+ /*
+ * Test method for 'org.acegisecurity.providers.openid.OpenIDAuthenticationProvider.supports(Class)'
+ */
+ public void testSupports() {
+ OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
+ provider.setSsoAuthoritiesPopulator(new MockAuthoritiesPopulator());
+
+ assertTrue(provider.supports(OpenIDAuthenticationToken.class));
+ }
+
+ public void testValidation() throws Exception {
+ OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider();
+ provider.setSsoAuthoritiesPopulator(new MockAuthoritiesPopulator());
+ provider.afterPropertiesSet();
+
+ provider.setSsoAuthoritiesPopulator(null);
+
+ try {
+ provider.afterPropertiesSet();
+ fail("IllegalArgumentException expected, ssoAuthoritiesPopulator is null");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+ }
+}
diff --git a/sandbox/openid/src/test/java/org/acegisecurity/ui/openid/OpenIDResponseProcessingFilterTests.java b/sandbox/openid/src/test/java/org/acegisecurity/ui/openid/OpenIDResponseProcessingFilterTests.java
new file mode 100644
index 0000000000..6c2046d6e4
--- /dev/null
+++ b/sandbox/openid/src/test/java/org/acegisecurity/ui/openid/OpenIDResponseProcessingFilterTests.java
@@ -0,0 +1,139 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.ui.openid;
+
+import junit.framework.TestCase;
+
+import org.acegisecurity.AbstractAuthenticationManager;
+import org.acegisecurity.Authentication;
+import org.acegisecurity.AuthenticationException;
+import org.acegisecurity.BadCredentialsException;
+
+import org.acegisecurity.providers.cas.CasAuthoritiesPopulator;
+import org.acegisecurity.providers.openid.MockAuthoritiesPopulator;
+import org.acegisecurity.providers.openid.OpenIDAuthenticationStatus;
+import org.acegisecurity.providers.openid.OpenIDAuthenticationToken;
+
+import org.acegisecurity.ui.openid.consumers.MockOpenIDConsumer;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+
+
+/**
+ * Tests {@link OpenIDResponseProcessingFilter}
+ *
+ * @author Robin Bramley, Opsera Ltd
+ */
+public class OpenIDResponseProcessingFilterTests extends TestCase {
+ //~ Static fields/initializers =====================================================================================
+
+ private static final String USERNAME = "user.acegiopenid.com";
+
+ //~ Methods ========================================================================================================
+
+ /*
+ * Test method for 'org.acegisecurity.ui.openid.OpenIDResponseProcessingFilter.attemptAuthentication(HttpServletRequest)'
+ */
+ public void testAttemptAuthenticationFailure() {
+ // set up mock objects
+ MockOpenIDAuthenticationManager mockAuthManager = new MockOpenIDAuthenticationManager(false);
+
+ OpenIDAuthenticationToken token = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.FAILURE, USERNAME, "");
+ MockOpenIDConsumer mockConsumer = new MockOpenIDConsumer();
+ mockConsumer.setToken(token);
+
+ MockHttpServletRequest req = new MockHttpServletRequest();
+
+ OpenIDResponseProcessingFilter filter = new OpenIDResponseProcessingFilter();
+ filter.setConsumer(mockConsumer);
+ filter.setAuthenticationManager(mockAuthManager);
+
+ // run test
+ try {
+ filter.attemptAuthentication(req);
+ fail("Should've thrown exception");
+ } catch (BadCredentialsException expected) {
+ assertEquals("MockOpenIDAuthenticationManager instructed to deny access", expected.getMessage());
+ }
+ }
+
+ /*
+ * Test method for 'org.acegisecurity.ui.openid.OpenIDResponseProcessingFilter.attemptAuthentication(HttpServletRequest)'
+ */
+ public void testAttemptAuthenticationHttpServletRequest() {
+ // set up mock objects
+ MockOpenIDAuthenticationManager mockAuthManager = new MockOpenIDAuthenticationManager(true);
+
+ OpenIDAuthenticationToken token = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SUCCESS, USERNAME, "");
+ MockOpenIDConsumer mockConsumer = new MockOpenIDConsumer();
+ mockConsumer.setToken(token);
+
+ MockHttpServletRequest req = new MockHttpServletRequest();
+
+ OpenIDResponseProcessingFilter filter = new OpenIDResponseProcessingFilter();
+ filter.setConsumer(mockConsumer);
+ filter.setAuthenticationManager(mockAuthManager);
+
+ // run test
+ Authentication authentication = filter.attemptAuthentication(req);
+
+ // assertions
+ assertNotNull(authentication);
+ assertTrue(authentication.isAuthenticated());
+ assertTrue(authentication instanceof OpenIDAuthenticationToken);
+ assertNotNull(authentication.getPrincipal());
+ assertEquals(USERNAME, authentication.getPrincipal());
+ assertNotNull(authentication.getAuthorities());
+ assertTrue(authentication.getAuthorities().length > 0);
+ assertTrue(((OpenIDAuthenticationToken) authentication).getStatus() == OpenIDAuthenticationStatus.SUCCESS);
+ assertTrue(((OpenIDAuthenticationToken) authentication).getMessage() == null);
+ }
+
+ /*
+ * Test method for 'org.acegisecurity.ui.openid.OpenIDResponseProcessingFilter.getDefaultFilterProcessesUrl()'
+ */
+ public void testGetDefaultFilterProcessesUrl() {
+ OpenIDResponseProcessingFilter filter = new OpenIDResponseProcessingFilter();
+ assertEquals("/j_acegi_openid_security_check", filter.getDefaultFilterProcessesUrl());
+ }
+
+ //~ Inner Classes ==================================================================================================
+
+ // private mock AuthenticationManager
+ private class MockOpenIDAuthenticationManager extends AbstractAuthenticationManager {
+ private CasAuthoritiesPopulator ssoAuthoritiesPopulator;
+ private boolean grantAccess = true;
+
+ public MockOpenIDAuthenticationManager(boolean grantAccess) {
+ this.grantAccess = grantAccess;
+ ssoAuthoritiesPopulator = new MockAuthoritiesPopulator();
+ }
+
+ public MockOpenIDAuthenticationManager() {
+ super();
+ ssoAuthoritiesPopulator = new MockAuthoritiesPopulator();
+ }
+
+ public Authentication doAuthentication(Authentication authentication)
+ throws AuthenticationException {
+ if (grantAccess) {
+ return new OpenIDAuthenticationToken(ssoAuthoritiesPopulator.getUserDetails(USERNAME).getAuthorities(),
+ OpenIDAuthenticationStatus.SUCCESS, USERNAME);
+ } else {
+ throw new BadCredentialsException("MockOpenIDAuthenticationManager instructed to deny access");
+ }
+ }
+ }
+}
diff --git a/sandbox/openid/src/test/java/org/acegisecurity/ui/openid/consumers/MockOpenIDConsumer.java b/sandbox/openid/src/test/java/org/acegisecurity/ui/openid/consumers/MockOpenIDConsumer.java
new file mode 100644
index 0000000000..616d63ae06
--- /dev/null
+++ b/sandbox/openid/src/test/java/org/acegisecurity/ui/openid/consumers/MockOpenIDConsumer.java
@@ -0,0 +1,78 @@
+/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.acegisecurity.ui.openid.consumers;
+
+import org.acegisecurity.providers.openid.OpenIDAuthenticationToken;
+
+import org.acegisecurity.ui.openid.OpenIDConsumer;
+import org.acegisecurity.ui.openid.OpenIDConsumerException;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author Robin Bramley, Opsera Ltd
+ */
+public class MockOpenIDConsumer implements OpenIDConsumer {
+ //~ Instance fields ================================================================================================
+
+ private OpenIDAuthenticationToken token;
+ private String redirectUrl;
+
+ //~ Methods ========================================================================================================
+
+ /* (non-Javadoc)
+ * @see org.acegisecurity.ui.openid.OpenIDConsumer#beginConsumption(javax.servlet.http.HttpServletRequest, java.lang.String)
+ */
+ public String beginConsumption(HttpServletRequest req, String identityUrl)
+ throws OpenIDConsumerException {
+ return redirectUrl;
+ }
+
+ /* (non-Javadoc)
+ * @see org.acegisecurity.ui.openid.OpenIDConsumer#endConsumption(javax.servlet.http.HttpServletRequest)
+ */
+ public OpenIDAuthenticationToken endConsumption(HttpServletRequest req)
+ throws OpenIDConsumerException {
+ return token;
+ }
+
+ /**
+ * Set the redirectUrl to be returned by beginConsumption
+ *
+ * @param redirectUrl
+ */
+ public void setRedirectUrl(String redirectUrl) {
+ this.redirectUrl = redirectUrl;
+ }
+
+ /* (non-Javadoc)
+ * @see org.acegisecurity.ui.openid.OpenIDConsumer#setReturnToUrl(java.lang.String)
+ */
+ public void setReturnToUrl(String returnToUrl) {
+ // TODO Auto-generated method stub
+ }
+
+ /**
+ * Set the token to be returned by endConsumption
+ *
+ * @param token
+ */
+ public void setToken(OpenIDAuthenticationToken token) {
+ this.token = token;
+ }
+}
diff --git a/sandbox/pom.xml b/sandbox/pom.xml
index 77c17d8eed..7d37f589ea 100644
--- a/sandbox/pom.xml
+++ b/sandbox/pom.xml
@@ -20,6 +20,7 @@
webwork
+ openid
other