我打算将CAS服务器从3.5.x升级到使用CAS协议3.0的5.3.x。但是,CAS客户端仍使用CAS协议2.0。问题在于客户端无法接收服务器传递的属性。
服务器由CAS Maven WAR Overlay(版本:5.3)构建。客户端是使用springboot构建的。
这是客户端的一些代码。
pom.xml:
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.4.1</version>
</dependency>
配置:
@Bean
public FilterRegistrationBean validationFilterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
Map<String, String> initParameters = new HashMap<>(2);
initParameters.put("casServerUrlPrefix", "http://localhost:8080/cas");
initParameters.put("serverName", "http://localhost:8081");
registrationBean.setFilter(new Cas20ProxyReceivingTicketValidationFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setInitParameters(initParameters);
registrationBean.setOrder(3);
return registrationBean;
}
控制器:
@RequestMapping("/index")
public String index(HttpServletRequest request, ModelMap modelMap) {
PrintStream out = System.out;
AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
if (principal != null) {
modelMap.put("principal", principal);
final Map attributes = principal.getAttributes(); // empty
if (attributes != null) {
out.println("attributes:" + attributes);
modelMap.put("attributes", attributes);
}
}
return "index";
}
如果将过滤器从Cas20ProxyReceivingTicketValidationFilter
更改为Cas30ProxyReceivingTicketValidationFilter
,就可以了。但是还有其他解决方案,这样我就不需要升级客户端代码了吗?
答案 0 :(得分:0)
我解决了这个问题!使用cas服务器进行一些更新。
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-core-web-api</artifactId>
<version>${cas.version}</version>
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-validation</artifactId>
<version>${cas.version}</version>
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-core-util-api</artifactId>
<version>${cas.version}</version>
</dependency>
org.apereo.cas.web.view.Cas20ResponseView
的类org.apereo.cas.web.view.Cas30ResponseView
。package org.apereo.cas.web.view;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.CasProtocolConstants;
import org.apereo.cas.CasViewConstants;
import org.apereo.cas.authentication.AuthenticationAttributeReleasePolicy;
import org.apereo.cas.authentication.AuthenticationServiceSelectionPlan;
import org.apereo.cas.authentication.ProtocolAttributeEncoder;
import org.apereo.cas.authentication.principal.Service;
import org.apereo.cas.services.RegisteredService;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.services.web.view.AbstractDelegatingCasView;
import org.apereo.cas.util.CollectionUtils;
import org.apereo.cas.validation.CasProtocolAttributesRenderer;
import org.apereo.cas.web.view.attributes.DefaultCas30ProtocolAttributesRenderer;
import org.apereo.cas.web.view.attributes.InlinedCas30ProtocolAttributesRenderer;
import org.springframework.web.servlet.View;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 参照Cas30ResponseView重写Cas20ResponseView,以便能够向protocol2.0的客户端返回属性。
* 在构造方法中手动设置以下两个属性
* this.releaseProtocolAttributes = true;
* this.attributesRenderer = new DefaultCas30ProtocolAttributesRenderer();
*
* @author duqian
* @date 2019/5/3
*/
@Slf4j
public class Cas20ResponseView extends AbstractDelegatingCasView {
/**
* The Service selection strategy.
*/
protected final AuthenticationServiceSelectionPlan authenticationRequestServiceSelectionStrategies;
private final CasProtocolAttributesRenderer attributesRenderer;
private final boolean releaseProtocolAttributes;
public Cas20ResponseView(final boolean successResponse,
final ProtocolAttributeEncoder protocolAttributeEncoder,
final ServicesManager servicesManager,
final String authenticationContextAttribute,
final View view,
final AuthenticationAttributeReleasePolicy authenticationAttributeReleasePolicy,
final AuthenticationServiceSelectionPlan serviceSelectionStrategy) {
super(successResponse, protocolAttributeEncoder, servicesManager, authenticationContextAttribute, view, authenticationAttributeReleasePolicy);
this.authenticationRequestServiceSelectionStrategies = serviceSelectionStrategy;
this.releaseProtocolAttributes = true;
this.attributesRenderer = new DefaultCas30ProtocolAttributesRenderer();
}
@Override
protected void prepareMergedOutputModel(final Map<String, Object> model, final HttpServletRequest request,
final HttpServletResponse response) throws Exception {
super.putIntoModel(model, CasViewConstants.MODEL_ATTRIBUTE_NAME_PRINCIPAL, getPrincipal(model));
super.putIntoModel(model, CasViewConstants.MODEL_ATTRIBUTE_NAME_CHAINED_AUTHENTICATIONS, getChainedAuthentications(model));
super.putIntoModel(model, CasViewConstants.MODEL_ATTRIBUTE_NAME_PRIMARY_AUTHENTICATION, getPrimaryAuthenticationFrom(model));
LOGGER.debug("Prepared CAS response output model with attribute names [{}]", model.keySet());
final Service service = authenticationRequestServiceSelectionStrategies.resolveService(getServiceFrom(model));
final RegisteredService registeredService = this.servicesManager.findServiceBy(service);
final Map<String, Object> principalAttributes = getCasPrincipalAttributes(model, registeredService);
final Map<String, Object> attributes = new HashMap<>(principalAttributes);
LOGGER.debug("Processed principal attributes from the output model to be [{}]", principalAttributes.keySet());
if (this.releaseProtocolAttributes) {
LOGGER.debug("CAS is configured to release protocol-level attributes. Processing...");
final Map<String, Object> protocolAttributes = getCasProtocolAuthenticationAttributes(model, registeredService);
attributes.putAll(protocolAttributes);
LOGGER.debug("Processed protocol/authentication attributes from the output model to be [{}]", protocolAttributes.keySet());
}
decideIfCredentialPasswordShouldBeReleasedAsAttribute(attributes, model, registeredService);
decideIfProxyGrantingTicketShouldBeReleasedAsAttribute(attributes, model, registeredService);
LOGGER.debug("Final collection of attributes for the response are [{}].", attributes.keySet());
putCasResponseAttributesIntoModel(model, attributes, registeredService);
}
/**
* Put cas authentication attributes into model.
*
* @param model the model
* @param registeredService the registered service
* @return the cas authentication attributes
*/
protected Map<String, Object> getCasProtocolAuthenticationAttributes(final Map<String, Object> model,
final RegisteredService registeredService) {
if (!registeredService.getAttributeReleasePolicy().isAuthorizedToReleaseAuthenticationAttributes()) {
LOGGER.debug("Attribute release policy for service [{}] is configured to never release any attributes", registeredService);
return new LinkedHashMap<>(0);
}
final Map<String, Object> filteredAuthenticationAttributes = authenticationAttributeReleasePolicy
.getAuthenticationAttributesForRelease(getPrimaryAuthenticationFrom(model));
filterCasProtocolAttributes(model, filteredAuthenticationAttributes);
final String contextProvider = getSatisfiedMultifactorAuthenticationProviderId(model);
if (StringUtils.isNotBlank(contextProvider) && StringUtils.isNotBlank(authenticationContextAttribute)) {
filteredAuthenticationAttributes.put(this.authenticationContextAttribute, CollectionUtils.wrap(contextProvider));
}
return filteredAuthenticationAttributes;
}
private void filterCasProtocolAttributes(final Map<String, Object> model, final Map<String, Object> filteredAuthenticationAttributes) {
filteredAuthenticationAttributes.put(CasProtocolConstants.VALIDATION_CAS_MODEL_ATTRIBUTE_NAME_AUTHENTICATION_DATE,
CollectionUtils.wrap(getAuthenticationDate(model)));
filteredAuthenticationAttributes.put(CasProtocolConstants.VALIDATION_CAS_MODEL_ATTRIBUTE_NAME_FROM_NEW_LOGIN,
CollectionUtils.wrap(isAssertionBackedByNewLogin(model)));
filteredAuthenticationAttributes.put(CasProtocolConstants.VALIDATION_REMEMBER_ME_ATTRIBUTE_NAME,
CollectionUtils.wrap(isRememberMeAuthentication(model)));
}
/**
* Put cas principal attributes into model.
*
* @param model the model
* @param registeredService the registered service
* @return the cas principal attributes
*/
protected Map<String, Object> getCasPrincipalAttributes(final Map<String, Object> model, final RegisteredService registeredService) {
return super.getPrincipalAttributesAsMultiValuedAttributes(model);
}
/**
* Put cas response attributes into model.
*
* @param model the model
* @param attributes the attributes
* @param registeredService the registered service
*/
protected void putCasResponseAttributesIntoModel(final Map<String, Object> model,
final Map<String, Object> attributes,
final RegisteredService registeredService) {
LOGGER.debug("Beginning to encode attributes for the response");
final Map<String, Object> encodedAttributes = this.protocolAttributeEncoder.encodeAttributes(attributes, registeredService);
LOGGER.debug("Encoded attributes for the response are [{}]", encodedAttributes);
super.putIntoModel(model, CasProtocolConstants.VALIDATION_CAS_MODEL_ATTRIBUTE_NAME_ATTRIBUTES, encodedAttributes);
final Collection<String> formattedAttributes = this.attributesRenderer.render(encodedAttributes);
super.putIntoModel(model, CasProtocolConstants.VALIDATION_CAS_MODEL_ATTRIBUTE_NAME_FORMATTED_ATTRIBUTES, formattedAttributes);
}
}
templates/protocol/2.0/casServiceValidationSuccess.html
指的是templates/protocol/3.0/casServiceValidationSuccess.html
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationSuccess>
<cas:user th:text="${principal.id}"/>
<cas:proxyGrantingTicket th:if="${pgtIou}" th:text="${pgtIou}"/>
<cas:proxies th:if="${not #lists.isEmpty(chainedAuthentications)}">
<cas:proxy th:each="proxy : ${chainedAuthentications}" th:text="${proxy.principal.id}"/>
</cas:proxies>
<!-- 从protocol3.0复制,向protocol2.0的客户端传递属性 -->
<cas:attributes th:if="${not #lists.isEmpty(formattedAttributes)}">
<div th:each="attr : ${formattedAttributes}" th:remove="tag">
<div th:utext="${attr}" th:remove="tag"/>
</div>
</cas:attributes>
<!-- 从protocol3.0复制,向protocol2.0的客户端传递属性 end -->
</cas:authenticationSuccess>
</cas:serviceResponse>
推荐人:https://blog.csdn.net/eric520zenobia/article/details/78105232