Commit e2418393 authored by Misagh Moayyed's avatar Misagh Moayyed
Browse files

Merge pull request #1169 from Unicon/response-builders

Refactor CAS service responses: use builders
parents 2f532365 4a6ebdb9
/*
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you 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 the following location:
*
* 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.jasig.cas.authentication.principal;
import java.io.Serializable;
/**
* Represents the task of building a CAS response
* that is returned by a service.
* @author Misagh Moayyed
* @param <T> the type parameter
* @since 4.2.0
*/
public interface ResponseBuilder<T extends WebApplicationService> extends Serializable {
/**
* Build response. The implementation must produce
* a response that is based on the type passed. Given
* the protocol used, the ticket id may be passed
* as part of the response. If the response type
* is not recognized, an error must be thrown back.
*
* @param service the service
* @param ticketId the ticket id
* @return the response
*/
Response build(T service, String ticketId);
}
...@@ -54,18 +54,23 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi ...@@ -54,18 +54,23 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi
private boolean loggedOutAlready; private boolean loggedOutAlready;
private final ResponseBuilder<WebApplicationService> responseBuilder;
/** /**
* Instantiates a new abstract web application service. * Instantiates a new abstract web application service.
* *
* @param id the id * @param id the id
* @param originalUrl the original url * @param originalUrl the original url
* @param artifactId the artifact id * @param artifactId the artifact id
* @param responseBuilder the response builder
*/ */
protected AbstractWebApplicationService(final String id, final String originalUrl, protected AbstractWebApplicationService(final String id, final String originalUrl,
final String artifactId) { final String artifactId, final ResponseBuilder<WebApplicationService> responseBuilder) {
this.id = id; this.id = id;
this.originalUrl = originalUrl; this.originalUrl = originalUrl;
this.artifactId = artifactId; this.artifactId = artifactId;
this.responseBuilder = responseBuilder;
} }
@Override @Override
...@@ -73,14 +78,17 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi ...@@ -73,14 +78,17 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi
return this.id; return this.id;
} }
@Override
public final String getId() { public final String getId() {
return this.id; return this.id;
} }
@Override
public final String getArtifactId() { public final String getArtifactId() {
return this.artifactId; return this.artifactId;
} }
@Override
public final Map<String, Object> getAttributes() { public final Map<String, Object> getAttributes() {
return EMPTY_MAP; return EMPTY_MAP;
} }
...@@ -91,6 +99,7 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi ...@@ -91,6 +99,7 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi
* *
* @return the original url provided. * @return the original url provided.
*/ */
@Override
public final String getOriginalUrl() { public final String getOriginalUrl() {
return this.originalUrl; return this.originalUrl;
} }
...@@ -117,10 +126,11 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi ...@@ -117,10 +126,11 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi
.toHashCode(); .toHashCode();
} }
protected Principal getPrincipal() { public Principal getPrincipal() {
return this.principal; return this.principal;
} }
@Override
public void setPrincipal(final Principal principal) { public void setPrincipal(final Principal principal) {
this.principal = principal; this.principal = principal;
} }
...@@ -144,6 +154,7 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi ...@@ -144,6 +154,7 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi
* *
* @return if the service is already logged out. * @return if the service is already logged out.
*/ */
@Override
public boolean isLoggedOutAlready() { public boolean isLoggedOutAlready() {
return loggedOutAlready; return loggedOutAlready;
} }
...@@ -153,7 +164,18 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi ...@@ -153,7 +164,18 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi
* *
* @param loggedOutAlready if the service is already logged out. * @param loggedOutAlready if the service is already logged out.
*/ */
@Override
public final void setLoggedOutAlready(final boolean loggedOutAlready) { public final void setLoggedOutAlready(final boolean loggedOutAlready) {
this.loggedOutAlready = loggedOutAlready; this.loggedOutAlready = loggedOutAlready;
} }
protected ResponseBuilder<? extends WebApplicationService> getResponseBuilder() {
return responseBuilder;
}
@Override
public Response getResponse(final String ticketId) {
return this.responseBuilder.build(this, ticketId);
}
} }
/*
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you 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 the following location:
*
* 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.jasig.cas.authentication.principal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
* Abstract response builder that provides wrappers for building
* post and redirect responses.
* @author Misagh Moayyed
* @since 4.2
*/
public abstract class AbstractWebApplicationServiceResponseBuilder implements ResponseBuilder<WebApplicationService> {
private static final long serialVersionUID = -4584738964007702423L;
protected final Logger logger = LoggerFactory.getLogger(getClass());
/**
* Build redirect.
*
* @param service the service
* @param parameters the parameters
* @return the response
*/
protected Response buildRedirect(final WebApplicationService service, final Map<String, String> parameters) {
return DefaultResponse.getRedirectResponse(service.getOriginalUrl(), parameters);
}
/**
* Build post.
*
* @param service the service
* @param parameters the parameters
* @return the response
*/
protected Response buildPost(final WebApplicationService service, final Map<String, String> parameters) {
return DefaultResponse.getPostResponse(service.getOriginalUrl(), parameters);
}
}
...@@ -18,12 +18,6 @@ ...@@ -18,12 +18,6 @@
*/ */
package org.jasig.cas.authentication.principal; package org.jasig.cas.authentication.principal;
import org.jasig.cas.CasProtocolConstants;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
/** /**
* Represents a service which wishes to use the CAS protocol. * Represents a service which wishes to use the CAS protocol.
* *
...@@ -34,7 +28,6 @@ public final class SimpleWebApplicationServiceImpl extends AbstractWebApplicatio ...@@ -34,7 +28,6 @@ public final class SimpleWebApplicationServiceImpl extends AbstractWebApplicatio
private static final long serialVersionUID = 8334068957483758042L; private static final long serialVersionUID = 8334068957483758042L;
private final Response.ResponseType responseType;
/** /**
* Instantiates a new simple web application service impl. * Instantiates a new simple web application service impl.
...@@ -42,26 +35,11 @@ public final class SimpleWebApplicationServiceImpl extends AbstractWebApplicatio ...@@ -42,26 +35,11 @@ public final class SimpleWebApplicationServiceImpl extends AbstractWebApplicatio
* @param id the id * @param id the id
* @param originalUrl the original url * @param originalUrl the original url
* @param artifactId the artifact id * @param artifactId the artifact id
* @param responseType the response type * @param responseBuilder the response builder
*/ */
protected SimpleWebApplicationServiceImpl(final String id, protected SimpleWebApplicationServiceImpl(final String id, final String originalUrl, final String artifactId,
final String originalUrl, final String artifactId, final ResponseBuilder<WebApplicationService> responseBuilder) {
final Response.ResponseType responseType) { super(id, originalUrl, artifactId, responseBuilder);
super(id, originalUrl, artifactId);
this.responseType = responseType;
}
@Override
public Response getResponse(final String ticketId) {
final Map<String, String> parameters = new HashMap<>();
if (StringUtils.hasText(ticketId)) {
parameters.put(CasProtocolConstants.PARAMETER_TICKET, ticketId);
}
if (Response.ResponseType.POST == this.responseType) {
return DefaultResponse.getPostResponse(getOriginalUrl(), parameters);
}
return DefaultResponse.getRedirectResponse(getOriginalUrl(), parameters);
} }
} }
...@@ -55,9 +55,12 @@ public final class WebApplicationServiceFactory extends AbstractServiceFactory<W ...@@ -55,9 +55,12 @@ public final class WebApplicationServiceFactory extends AbstractServiceFactory<W
final String id = cleanupUrl(serviceToUse); final String id = cleanupUrl(serviceToUse);
final String artifactId = request.getParameter(CasProtocolConstants.PARAMETER_TICKET); final String artifactId = request.getParameter(CasProtocolConstants.PARAMETER_TICKET);
return new SimpleWebApplicationServiceImpl(id, serviceToUse, final Response.ResponseType type = "POST".equalsIgnoreCase(method) ? Response.ResponseType.POST
artifactId, "POST".equalsIgnoreCase(method) ? Response.ResponseType.POST : Response.ResponseType.REDIRECT;
: Response.ResponseType.REDIRECT);
final WebApplicationService webApplicationService = new SimpleWebApplicationServiceImpl(id, serviceToUse,
artifactId, new WebApplicationServiceResponseBuilder(type));
return webApplicationService;
} }
@Override @Override
......
/*
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you 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 the following location:
*
* 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.jasig.cas.authentication.principal;
import org.jasig.cas.CasProtocolConstants;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
* Default response builder that passes back the ticket
* id to the original url of the service based on the response type.
* @author Misagh Moayyed
* @since 4.2
*/
public class WebApplicationServiceResponseBuilder extends AbstractWebApplicationServiceResponseBuilder {
private static final long serialVersionUID = -851233878780818494L;
private final Response.ResponseType responseType;
/**
* Instantiates a new Web application service response builder.
* @param type the type
*/
public WebApplicationServiceResponseBuilder(final Response.ResponseType type) {
this.responseType = type;
}
@Override
public Response build(final WebApplicationService service, final String ticketId) {
final Map<String, String> parameters = new HashMap<>();
if (StringUtils.hasText(ticketId)) {
parameters.put(CasProtocolConstants.PARAMETER_TICKET, ticketId);
}
if (responseType.equals(Response.ResponseType.POST)) {
return buildPost(service, parameters);
}
if (responseType.equals(Response.ResponseType.REDIRECT)) {
return buildRedirect(service, parameters);
}
throw new IllegalArgumentException("Response type is valid. Only POST/REDIRECT are supported");
}
}
...@@ -18,18 +18,16 @@ ...@@ -18,18 +18,16 @@
*/ */
package org.jasig.cas.util.http; package org.jasig.cas.util.http;
import static org.junit.Assert.assertFalse; import org.apache.http.conn.ssl.NoopHostnameVerifier;
import static org.junit.Assert.assertTrue; import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.junit.Test;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
import org.apache.http.conn.ssl.NoopHostnameVerifier; import static org.junit.Assert.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.junit.Test;
/** /**
* Test cases for {@link SimpleHttpClient}. * Test cases for {@link SimpleHttpClient}.
...@@ -71,10 +69,13 @@ public class SimpleHttpClientTests { ...@@ -71,10 +69,13 @@ public class SimpleHttpClientTests {
private SSLConnectionSocketFactory getFriendlyToAllSSLSocketFactory() throws Exception { private SSLConnectionSocketFactory getFriendlyToAllSSLSocketFactory() throws Exception {
final TrustManager trm = new X509TrustManager() { final TrustManager trm = new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() { public X509Certificate[] getAcceptedIssuers() {
return null; return null;
} }
@Override
public void checkClientTrusted(final X509Certificate[] certs, final String authType) {} public void checkClientTrusted(final X509Certificate[] certs, final String authType) {}
@Override
public void checkServerTrusted(final X509Certificate[] certs, final String authType) {} public void checkServerTrusted(final X509Certificate[] certs, final String authType) {}
}; };
final SSLContext sc = SSLContext.getInstance("SSL"); final SSLContext sc = SSLContext.getInstance("SSL");
......
...@@ -66,6 +66,12 @@ ...@@ -66,6 +66,12 @@
<type>test-jar</type> <type>test-jar</type>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-server-webapp-support</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<properties> <properties>
......
...@@ -19,24 +19,11 @@ ...@@ -19,24 +19,11 @@
package org.jasig.cas.support.openid.authentication.principal; package org.jasig.cas.support.openid.authentication.principal;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.jasig.cas.CentralAuthenticationService;
import org.jasig.cas.authentication.principal.AbstractWebApplicationService; import org.jasig.cas.authentication.principal.AbstractWebApplicationService;
import org.jasig.cas.authentication.principal.DefaultResponse; import org.jasig.cas.authentication.principal.ResponseBuilder;
import org.jasig.cas.authentication.principal.Response; import org.jasig.cas.authentication.principal.WebApplicationService;
import org.jasig.cas.support.openid.OpenIdProtocolConstants;
import org.jasig.cas.ticket.AbstractTicketException;
import org.jasig.cas.util.ApplicationContextProvider;
import org.jasig.cas.validation.Assertion;
import org.openid4java.association.Association;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.Message;
import org.openid4java.message.MessageException;
import org.openid4java.message.ParameterList;
import org.openid4java.server.ServerManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/** /**
* @author Scott Battaglia * @author Scott Battaglia
...@@ -51,12 +38,6 @@ public final class OpenIdService extends AbstractWebApplicationService { ...@@ -51,12 +38,6 @@ public final class OpenIdService extends AbstractWebApplicationService {
private final String identity; private final String identity;
private final String artifactId;
private final ParameterList requestParameters;
private final String openIdPrefixUrl;
/** /**
* Instantiates a new OpenID service. * Instantiates a new OpenID service.
* *
...@@ -64,100 +45,15 @@ public final class OpenIdService extends AbstractWebApplicationService { ...@@ -64,100 +45,15 @@ public final class OpenIdService extends AbstractWebApplicationService {
* @param originalUrl the original url * @param originalUrl the original url
* @param artifactId the artifact id * @param artifactId the artifact id
* @param openIdIdentity the OpenID identity * @param openIdIdentity the OpenID identity
* @param signature the signature * @param responseBuilder the response builder
* @param parameterList the parameter list
* @param openIdPrefixUrl the prefix url for OpenID
*/ */
protected OpenIdService(final String id, final String originalUrl, protected OpenIdService(final String id, final String originalUrl,
final String artifactId, final String openIdIdentity, final String artifactId, final String openIdIdentity,
final String signature, final ParameterList parameterList, final ResponseBuilder<WebApplicationService> responseBuilder) {
final String openIdPrefixUrl) { super(id, originalUrl, artifactId, responseBuilder);
super(id, originalUrl, artifactId);
this.identity = openIdIdentity; this.identity = openIdIdentity;
this.artifactId = artifactId;
this.requestParameters = parameterList;
this.openIdPrefixUrl = openIdPrefixUrl;
} }
/**
* Generates an Openid response.
* If no ticketId is found, response is negative.
* If we have a ticket id, then we check if we have an association.
* If so, we ask OpenId server manager to generate the answer according with the existing association.
* If not, we send back an answer with the ticket id as association handle.
* This will force the consumer to ask a verification, which will validate the service ticket.
* @param ticketId the service ticket to provide to the service.
* @return the generated authentication answer
*/
@Override
public Response getResponse(final String ticketId) {
final Map<String, String> parameters = new HashMap<>();
if (ticketId != null) {