cas自带的登出是通过登出地址后面接的service地址进行跳转,但是对于service没有进行验证,这边我们网络渗透测试后说可能被钓鱼需要进行验证所以开始了以下操作。
1找资料
首先到cas官网找,发现项目有自带的是否跳转,跳转地址参数名称,跳转地址配置等数据
2.找代码 其中重点配置的是否跳转参数,我们知道java的bean可以将读取配置的-视为下一个字母大写,所以我在jar包中搜索followServiceRedirects
还有在实体类中看到需要引入包
所以在build.gradle中的dependencies下层次
加入
implementation "org.apereo.cas:cas-server-core-logout:${casServerVersion}"
具体位置如下
3.代码解读
圈中的地方为判断service地址是不是为空,并且followServiceRedirects为真 进行跳转
这就表明只要我们在这边加个查询 跳转的service是不是在自己的数据库里面就成,具体怎么做我就不赘述了,大家需求不同,因为我这边开始会将数据载入在servicesManager中 我直接读就行,我们来看看如何替换掉它,
其中点击方法发现只有3个地方有写到这个类,其中第一个是自身,后面两个来自一个启动配置
然后就看到这个bean 是新建这个类的东西,而且上面使用了@ConditionalOnMissingBean
也就是说只要我再写一个bean叫同一个名字,他就会加载我的了,所以我写了个config
继续点击方法看看引用
发现下面那个方法有加载,所以我重写了这俩到一个配置文件,并切新建了一个自定义规则的文件
package com.fgi.logout.cofig;
import com.fgi.logout.strategy.CustomLogoutRedirectionStrategy;
import org.apereo.cas.authentication.principal.ServiceFactory;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.logout.LogoutExecutionPlanConfigurer;
import org.apereo.cas.logout.LogoutRedirectionStrategy;
import org.apereo.cas.logout.config.CasCoreLogoutConfiguration;
import org.apereo.cas.logout.slo.SingleLogoutServiceLogoutUrlBuilder;
import org.apereo.cas.ticket.registry.TicketRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author LinZuo
* @date 2023-06-07$ $
*/
@Configuration("logoutRedirectionConfiguration")
public class LogoutRedirectionConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(SingleLogoutTriggerConfiguration.class);
@Autowired
private CasCoreLogoutConfiguration casCoreLogoutConfiguration;
@Autowired
private CasConfigurationProperties casProperties;
@Autowired
@Qualifier("ticketRegistry")
private ObjectProvider<TicketRegistry> ticketRegistry;
@Autowired
@Qualifier("webApplicationServiceFactory")
private ObjectProvider<ServiceFactory> webApplicationServiceFactory;
@Autowired
@Qualifier("singleLogoutServiceLogoutUrlBuilder")
private ObjectProvider<SingleLogoutServiceLogoutUrlBuilder> singleLogoutServiceLogoutUrlBuilder;
@Bean
@RefreshScope
@ConditionalOnMissingBean(name = "casCoreLogoutExecutionPlanConfigurer")
public LogoutExecutionPlanConfigurer casCoreLogoutExecutionPlanConfigurer() {
return plan -> {
plan.registerSingleLogoutServiceMessageHandler(casCoreLogoutConfiguration.defaultSingleLogoutServiceMessageHandler());
plan.registerLogoutRedirectionStrategy(defaultLogoutRedirectionStrategy());
if (casProperties.getLogout().isRemoveDescendantTickets()) {
LOGGER.debug("CAS is configured to remove descendant tickets of the ticket-granting tickets");
plan.registerLogoutPostProcessor(ticketGrantingTicket -> ticketGrantingTicket.getDescendantTickets()
.forEach(t -> {
LOGGER.debug("Deleting ticket [{}] from the registry as a descendant of [{}]", t, ticketGrantingTicket.getId());
ticketRegistry.getObject().deleteTicket(t);
}));
}
};
}
@Bean
@RefreshScope
@ConditionalOnMissingBean(name = "defaultLogoutRedirectionStrategy")
public LogoutRedirectionStrategy defaultLogoutRedirectionStrategy() {
return new CustomLogoutRedirectionStrategy(webApplicationServiceFactory.getObject(),
casProperties.getLogout(), singleLogoutServiceLogoutUrlBuilder.getObject());
}
}
package com.fgi.logout.strategy;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.fgi.service.ServiceManagerUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.authentication.principal.ServiceFactory;
import org.apereo.cas.authentication.principal.WebApplicationService;
import org.apereo.cas.configuration.model.core.logout.LogoutProperties;
import org.apereo.cas.logout.LogoutRedirectionStrategy;
import org.apereo.cas.logout.slo.SingleLogoutServiceLogoutUrlBuilder;
import org.apereo.cas.services.RegisteredService;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.web.support.WebUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.webflow.execution.RequestContext;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
/**
* This is {@link CustomLogoutRedirectionStrategy}.
*
* @author Misagh Moayyed
* @since 6.3.0
*/
@RequiredArgsConstructor
@Slf4j
public class CustomLogoutRedirectionStrategy implements LogoutRedirectionStrategy {
private final ServiceFactory<WebApplicationService> webApplicationServiceFactory;
private final LogoutProperties logoutProperties;
private final SingleLogoutServiceLogoutUrlBuilder singleLogoutServiceLogoutUrlBuilder;
@Resource
@Qualifier("servicesManager")
private ServicesManager servicesManager;
@Override
public boolean supports(final RequestContext context) {
return context != null;
}
@Override
public void handle(final RequestContext requestContext) {
val request = WebUtils.getHttpServletRequestFromExternalWebflowContext(requestContext);
val paramName = logoutProperties.getRedirectParameter();
log.trace("Using parameter name [{}] to detect destination service, if any", paramName);
val service = requestContext.getRequestParameters().get(paramName);
log.trace("Located target service [{}] for redirection after logout", service);
// 添加的代码 判断登出地址中是否有当前跳转的地址 s
Collection<RegisteredService> list = servicesManager.getAllServices();
List<String> serviceIds = ServiceManagerUtil.getServiceId(service);
boolean exists = list.stream().anyMatch(s-> {
if(CollectionUtil.isEmpty(serviceIds)){
return false;
}
return StrUtil.isNotBlank(s.getLogoutUrl())&& s.getRedirectUrl().equals(serviceIds.get(0));
});
// 添加的代码 判断登出地址中是否有当前跳转的地址 e
val authorizedRedirectUrlFromRequest = WebUtils.getLogoutRedirectUrl(request, String.class);
if (StringUtils.isNotBlank(service) && logoutProperties.isFollowServiceRedirects()&&exists) {
val webAppService = webApplicationServiceFactory.createService(service);
if (singleLogoutServiceLogoutUrlBuilder.isServiceAuthorized(webAppService, Optional.of(request))) {
log.debug("Redirecting to logout URL [{}]", service);
WebUtils.putLogoutRedirectUrl(requestContext, service);
} else {
log.warn("Cannot redirect to [{}] given the service is unauthorized to use CAS. "
+ "Ensure the service is registered with CAS and is enabled to allow access", service);
}
} else if (StringUtils.isNotBlank(authorizedRedirectUrlFromRequest)) {
WebUtils.putLogoutRedirectUrl(requestContext, authorizedRedirectUrlFromRequest);
} else {
log.debug("No target service is located for redirection after logout, or following service redirects is disabled");
}
}
}
并且在H:\sso-server\src\main\resources\META-INF\spring.factories中添加加载
这样 就可以登出时候判断service跳转地址是不是自己想要的了。