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

Merge pull request #1118 from Unicon/service-factories

Allow "ServiceFactory"s to create CAS Services
parents fe03f630 731381c1
......@@ -19,7 +19,7 @@
package org.jasig.cas.services.web;
import org.jasig.cas.authentication.principal.Service;
import org.jasig.cas.authentication.principal.SimpleWebApplicationServiceImpl;
import org.jasig.cas.authentication.principal.WebApplicationServiceFactory;
import org.jasig.cas.services.RegexRegisteredService;
import org.jasig.cas.services.RegisteredService;
import org.jasig.cas.services.ServicesManager;
......@@ -65,7 +65,7 @@ public final class ManageRegisteredServicesMultiActionController extends Abstrac
public ManageRegisteredServicesMultiActionController(final ServicesManager servicesManager,
@Value("${cas-management.securityContext.serviceProperties.service}") final String defaultServiceUrl) {
super(servicesManager);
this.defaultService = new SimpleWebApplicationServiceImpl(defaultServiceUrl);
this.defaultService = new WebApplicationServiceFactory().createService(defaultServiceUrl);
}
/**
......
......@@ -57,6 +57,18 @@ public interface CasProtocolConstants {
/** Constant representing the renew parameter in the request. */
String PARAMETER_RENEW = "renew";
/** Constant representing the service parameter in the request. */
String PARAMETER_SERVICE = "service";
/** Constant representing the ticket parameter in the request. */
String PARAMETER_TICKET = "ticket";
/** Constant representing the targetService parameter in the request. */
String PARAMETER_TARGET_SERVICE = "targetService";
/** Constant representing the method parameter in the request. */
String PARAMETER_METHOD = "method";
/** CAS Protocol Error Codes. **/
/** Constant representing an invalid request for validation. */
......
/*
* 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 javax.servlet.http.HttpServletRequest;
/**
* The {@link ServiceFactory} is responsible for creating service objects.
* @author Misagh Moayyed
* @param <T> the type parameter
* @since 4.2
*/
public interface ServiceFactory<T extends Service> {
/**
* Create service object based on the parameters of the request.
*
* @param request the request
* @return the service
*/
T createService(HttpServletRequest request);
/**
* Create service based on an identifier.
*
* @param id the id
* @return the service object
*/
T createService(String id);
/**
* Create the service object based on an identifier.
* Allows the final service object to be casted to the desired service class
* that may not immediately inherit from {@link Service} itself.
*
* @param <T> the type parameter
* @param id the id
* @param clazz the clazz
* @return the t
*/
<T extends Service> T createService(String id, Class<? extends Service> clazz);
/**
* Create service based on the given parameters provided by the http request.
* Allows the final service object to be casted to the desired service class
* that may not immediately inherit from {@link Service} itself.
*
* @param <T> the type parameter
* @param request the request
* @param clazz the clazz
* @return the t
*/
<T extends Service> T createService(HttpServletRequest request, Class<? extends Service> clazz);
}
/*
* 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 javax.servlet.http.HttpServletRequest;
/**
* The {@link AbstractServiceFactory} is the parent class providing
* convenience methods for creating service objects.
*
* @author Misagh Moayyed
* @since 4.2
*/
public abstract class AbstractServiceFactory<T extends Service> implements ServiceFactory<T> {
/** Logger instance. */
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public <T1 extends Service> T1 createService(final String id, final Class<? extends Service> clazz) {
final Service service = createService(id);
if (!clazz.isAssignableFrom(service.getClass())) {
throw new ClassCastException("Service [" + service.getId()
+ " is of type " + service.getClass()
+ " when we were expecting " + clazz);
}
return (T1) service;
}
@Override
public <T1 extends Service> T1 createService(final HttpServletRequest request, final Class<? extends Service> clazz) {
final Service service = createService(request);
if (!clazz.isAssignableFrom(service.getClass())) {
throw new ClassCastException("Service [" + service.getId()
+ " is of type " + service.getClass()
+ " when we were expecting " + clazz);
}
return (T1) service;
}
/**
* Cleanup the url. Removes jsession ids and query strings.
*
* @param url the url
* @return sanitized url.
*/
protected static String cleanupUrl(final String url) {
if (url == null) {
return null;
}
final int jsessionPosition = url.indexOf(";jsession");
if (jsessionPosition == -1) {
return url;
}
final int questionMarkPosition = url.indexOf('?');
if (questionMarkPosition < jsessionPosition) {
return url.substring(0, url.indexOf(";jsession"));
}
return url.substring(0, jsessionPosition)
+ url.substring(questionMarkPosition);
}
}
......@@ -85,33 +85,6 @@ public abstract class AbstractWebApplicationService implements SingleLogoutServi
return EMPTY_MAP;
}
/**
* Cleanup the url. Removes jsession ids and query strings.
*
* @param url the url
* @return sanitized url.
*/
protected static String cleanupUrl(final String url) {
if (url == null) {
return null;
}
final int jsessionPosition = url.indexOf(";jsession");
if (jsessionPosition == -1) {
return url;
}
final int questionMarkPosition = url.indexOf('?');
if (questionMarkPosition < jsessionPosition) {
return url.substring(0, url.indexOf(";jsession"));
}
return url.substring(0, jsessionPosition)
+ url.substring(questionMarkPosition);
}
/**
* Return the original url provided (as <code>service</code> or <code>targetService</code> request parameter).
* Used to reconstruct the redirect url.
......
......@@ -18,9 +18,9 @@
*/
package org.jasig.cas.authentication.principal;
import org.jasig.cas.CasProtocolConstants;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
......@@ -34,25 +34,8 @@ public final class SimpleWebApplicationServiceImpl extends AbstractWebApplicatio
private static final long serialVersionUID = 8334068957483758042L;
private static final String CONST_PARAM_SERVICE = "service";
private static final String CONST_PARAM_TARGET_SERVICE = "targetService";
private static final String CONST_PARAM_TICKET = "ticket";
private static final String CONST_PARAM_METHOD = "method";
private final Response.ResponseType responseType;
/**
* Instantiates a new simple web application service impl.
*
* @param id the id
*/
public SimpleWebApplicationServiceImpl(final String id) {
this(id, id, null, null);
}
/**
* Instantiates a new simple web application service impl.
*
......@@ -61,52 +44,19 @@ public final class SimpleWebApplicationServiceImpl extends AbstractWebApplicatio
* @param artifactId the artifact id
* @param responseType the response type
*/
private SimpleWebApplicationServiceImpl(final String id,
protected SimpleWebApplicationServiceImpl(final String id,
final String originalUrl, final String artifactId,
final Response.ResponseType responseType) {
super(id, originalUrl, artifactId);
this.responseType = responseType;
}
/**
* Creates the service from the request.
*
* @param request the request
* @return the simple web application service impl
*/
public static SimpleWebApplicationServiceImpl createServiceFrom(
final HttpServletRequest request) {
final String targetService = request.getParameter(CONST_PARAM_TARGET_SERVICE);
final String service = request.getParameter(CONST_PARAM_SERVICE);
final String serviceAttribute = (String) request.getAttribute(CONST_PARAM_SERVICE);
final String method = request.getParameter(CONST_PARAM_METHOD);
final String serviceToUse;
if (StringUtils.hasText(targetService)) {
serviceToUse = targetService;
} else if (StringUtils.hasText(service)) {
serviceToUse = service;
} else {
serviceToUse = serviceAttribute;
}
if (!StringUtils.hasText(serviceToUse)) {
return null;
}
final String id = cleanupUrl(serviceToUse);
final String artifactId = request.getParameter(CONST_PARAM_TICKET);
return new SimpleWebApplicationServiceImpl(id, serviceToUse,
artifactId, "POST".equals(method) ? Response.ResponseType.POST
: Response.ResponseType.REDIRECT);
}
@Override
public Response getResponse(final String ticketId) {
final Map<String, String> parameters = new HashMap<>();
if (StringUtils.hasText(ticketId)) {
parameters.put(CONST_PARAM_TICKET, ticketId);
parameters.put(CasProtocolConstants.PARAMETER_TICKET, ticketId);
}
if (Response.ResponseType.POST == this.responseType) {
......
/*
* 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 javax.servlet.http.HttpServletRequest;
/**
* The {@link WebApplicationServiceFactory} is responsible for
* creating {@link WebApplicationService} objects.
*
* @author Misagh Moayyed
* @since 4.2
*/
public final class WebApplicationServiceFactory extends AbstractServiceFactory<WebApplicationService> {
@Override
public WebApplicationService createService(final HttpServletRequest request) {
final String targetService = request.getParameter(CasProtocolConstants.PARAMETER_TARGET_SERVICE);
final String service = request.getParameter(CasProtocolConstants.PARAMETER_SERVICE);
final String serviceAttribute = (String) request.getAttribute(CasProtocolConstants.PARAMETER_SERVICE);
final String method = request.getParameter(CasProtocolConstants.PARAMETER_METHOD);
final String serviceToUse;
if (StringUtils.hasText(targetService)) {
serviceToUse = targetService;
} else if (StringUtils.hasText(service)) {
serviceToUse = service;
} else {
serviceToUse = serviceAttribute;
}
if (!StringUtils.hasText(serviceToUse)) {
return null;
}
final String id = cleanupUrl(serviceToUse);
final String artifactId = request.getParameter(CasProtocolConstants.PARAMETER_TICKET);
return new SimpleWebApplicationServiceImpl(id, serviceToUse,
artifactId, "POST".equalsIgnoreCase(method) ? Response.ResponseType.POST
: Response.ResponseType.REDIRECT);
}
@Override
public WebApplicationService createService(final String id) {
return new SimpleWebApplicationServiceImpl(id, id, null, null);
}
}
......@@ -27,7 +27,7 @@ import org.jasig.cas.ticket.registry.AbstractDistributedTicketRegistry;
import org.jasig.cas.util.CipherExecutor;
import org.jasig.cas.util.CompressionUtils;
import javax.validation.constraints.Null;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.HashSet;
......@@ -44,7 +44,7 @@ import java.util.HashSet;
*/
public abstract class AbstractCrypticTicketRegistry extends AbstractDistributedTicketRegistry {
@Null
@Nullable
private CipherExecutor<byte[], byte[]> cipherExecutor;
/**
......
......@@ -54,6 +54,7 @@ public final class PrivateKeyFactoryBean extends AbstractFactoryBean<PrivateKey>
}
}
@Override
public Class getObjectType() {
return PrivateKey.class;
}
......
......@@ -21,6 +21,8 @@ package org.jasig.cas.web;
import org.jasig.cas.authentication.AuthenticationHandler;
import org.jasig.cas.authentication.principal.PrincipalResolver;
import org.jasig.cas.authentication.principal.Service;
import org.jasig.cas.authentication.principal.ServiceFactory;
import org.jasig.cas.services.RegisteredService;
import org.jasig.cas.services.ServicesManager;
import org.jasig.cas.util.UniqueTicketIdGenerator;
......@@ -201,6 +203,18 @@ public abstract class AbstractServletContextInitializer implements ServletContex
list.add(ext);
}
/**
* Add service factory.
*
* @param factory the factory
*/
protected void addServiceFactory(final ServiceFactory<? extends Service> factory) {
final List<ServiceFactory<? extends Service>> list =
applicationContext.getBean("serviceFactoryList", List.class);
list.add(factory);
}
/**
* Add service ticket unique id generator.
*
......
......@@ -18,12 +18,17 @@
*/
package org.jasig.cas.web.support;
import javax.servlet.http.HttpServletRequest;
import org.jasig.cas.authentication.principal.ServiceFactory;
import org.jasig.cas.authentication.principal.WebApplicationService;
import org.jasig.cas.authentication.principal.WebApplicationServiceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.Min;
import java.util.ArrayList;
import java.util.List;
/**
* Abstract class for handling argument extraction.
*
......@@ -33,10 +38,39 @@ import org.slf4j.LoggerFactory;
*/
public abstract class AbstractArgumentExtractor implements ArgumentExtractor {
/** Logger instance. */
protected final Logger logger = LoggerFactory.getLogger(getClass());
/** The factory responsible for creating service objects based on the arguments extracted. */
private final List<ServiceFactory<? extends WebApplicationService>> serviceFactory;
/**
* Logger instance.
* Instantiates a new argument extractor.
*/
protected final Logger logger = LoggerFactory.getLogger(getClass());
public AbstractArgumentExtractor() {
this(new WebApplicationServiceFactory());
}
/**
* Instantiates a new argument extractor.
*
* @param serviceFactory the service factory
*/
public AbstractArgumentExtractor(final ServiceFactory<? extends WebApplicationService> serviceFactory) {
this.serviceFactory = new ArrayList<>();
this.serviceFactory.add(serviceFactory);
}
/**
* Instantiates a new argument extractor.
*
* @param serviceFactoryList the service factory list
*/
public AbstractArgumentExtractor(@Min(1)
final List<ServiceFactory<? extends WebApplicationService>> serviceFactoryList) {
this.serviceFactory = new ArrayList<>();
this.serviceFactory.addAll(serviceFactoryList);
}
@Override
public final WebApplicationService extractService(final HttpServletRequest request) {
......@@ -57,5 +91,13 @@ public abstract class AbstractArgumentExtractor implements ArgumentExtractor {
* @param request the request
* @return the web application service
*/
protected abstract WebApplicationService extractServiceInternal(final HttpServletRequest request);
protected abstract WebApplicationService extractServiceInternal(HttpServletRequest request);
public final ServiceFactory<? extends WebApplicationService> getServiceFactory() {
return serviceFactory.get(0);
}
protected final List<ServiceFactory<? extends WebApplicationService>> getServiceFactories() {
return serviceFactory;
}
}
......@@ -16,23 +16,29 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas.web.support;
import javax.servlet.http.HttpServletRequest;
import org.jasig.cas.authentication.principal.SimpleWebApplicationServiceImpl;
import org.apache.commons.lang3.NotImplementedException;
import org.jasig.cas.authentication.principal.WebApplicationService;
import javax.servlet.http.HttpServletRequest;
/**
* @deprecated As of 4.2, use {@link DefaultArgumentExtractor}.
* Implements the traditional CAS2 protocol.
*
* @author Scott Battaglia
* @since 3.1
*/
@Deprecated
public final class CasArgumentExtractor extends AbstractArgumentExtractor {
@Override
public WebApplicationService extractServiceInternal(final HttpServletRequest request) {
return SimpleWebApplicationServiceImpl.createServiceFrom(request);
throw new NotImplementedException("This operation is not supported. "
+ "The class is deprecated and will be removed in future versions");
}
}
/*
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work