Я знаю, что это немного старое, но я просто должен был решить эту проблему очень и не мог найти что-нибудь в новых стеках.
У нас есть несколько сред, которые используют один и тот же сервис CAS (думаю, dev, qa, uat и локальные среды разработки); у нас есть возможность ударить по каждой среде из нескольких URL-адресов (через веб-сервер клиентской стороны через обратный прокси-сервер и непосредственно на внутренний сервер). Это означает, что указание одного URL-адреса в лучшем случае затруднено. Возможно, есть способ сделать это, но можно использовать динамический ServiceProperties.getService()
. Я, вероятно, добавлю какую-то проверку суффикса сервера, чтобы убедиться, что URL-адрес не был захвачен в какой-то момент.
Вот что я сделал, чтобы получить основной поток CAS работает независимо от URL, используемый для доступа к защищенному ресурсу ...
- Override
CasAuthenticationFilter
.
- Переопределить
CasAuthenticationProvider
.
setAuthenticateAllArtifacts(true)
на ServiceProperties
.
Вот длинная форма моей весенней конфигурации фасоли:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
public class CasSecurityConfiguration extends WebSecurityConfigurerAdapter {
Просто обычная конфигурация весной фасоль.
@Value("${cas.server.url:https://localhost:9443/cas}")
private String casServerUrl;
@Value("${cas.service.validation.uri:/webapi/j_spring_cas_security_check}")
private String casValidationUri;
@Value("${cas.provider.key:whatever_your_key}")
private String casProviderKey;
Некоторые внешние параметры конфигурации.
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(casValidationUri);
serviceProperties.setSendRenew(false);
serviceProperties.setAuthenticateAllArtifacts(true);
return serviceProperties;
}
Главное выше является setAuthenticateAllArtifacts(true)
вызов. Это позволит сделать валидатор билетной кассы использовать AuthenticationDetailsSource
реализацию, а не жестко закодированы ServiceProperties.getService()
вызова
@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
return new Cas20ServiceTicketValidator(casServerUrl);
}
Стандартный валидатора билет ..
@Resource
private UserDetailsService userDetailsService;
@Bean
public AuthenticationUserDetailsService authenticationUserDetailsService() {
return new AuthenticationUserDetailsService() {
@Override
public UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException {
String username = (token.getPrincipal() == null) ? "NONE_PROVIDED" : token.getName();
return userDetailsService.loadUserByUsername(username);
}
};
}
Стандартный крюк к существующему UserDetailsService
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(authenticationUserDetailsService());
casAuthenticationProvider.setServiceProperties(serviceProperties());
casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setKey(casProviderKey);
return casAuthenticationProvider;
}
Поставщик стандартной проверки подлинности
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setServiceProperties(serviceProperties());
casAuthenticationFilter.setAuthenticationDetailsSource(dynamicServiceResolver());
return casAuthenticationFilter;
}
Ключ здесь является dynamicServiceResolver()
установка ..
@Bean
AuthenticationDetailsSource<HttpServletRequest,
ServiceAuthenticationDetails> dynamicServiceResolver() {
return new AuthenticationDetailsSource<HttpServletRequest, ServiceAuthenticationDetails>() {
@Override
public ServiceAuthenticationDetails buildDetails(HttpServletRequest context) {
final String url = makeDynamicUrlFromRequest(serviceProperties());
return new ServiceAuthenticationDetails() {
@Override
public String getServiceUrl() {
return url;
}
};
}
};
}
Динамически создает URL службы от метода makeDynamicUrlFromRequest()
. Этот бит используется при проверке билетов.
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint() {
@Override
protected String createServiceUrl(final HttpServletRequest request, final HttpServletResponse response) {
return CommonUtils.constructServiceUrl(null, response, makeDynamicUrlFromRequest(serviceProperties())
, null, serviceProperties().getArtifactParameter(), false);
}
};
casAuthenticationEntryPoint.setLoginUrl(casServerUrl + "/login");
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
В этой части используется тот же динамический создатель URL, когда CAS хочет перенаправить на экран входа в систему.
private String makeDynamicUrlFromRequest(ServiceProperties serviceProperties){
return "https://howeverYouBuildYourOwnDynamicUrl.com";
}
Это все, что вы от него делаете. Я только передал в ServiceProperties для хранения URI службы, для которой мы настроены. Мы используем HATEAOS на задней стороне и есть реализация, как:
return UriComponentsBuilder.fromHttpUrl(
linkTo(methodOn(ExposedRestResource.class)
.aMethodOnThatResource(null)).withSelfRel().getHref())
.replacePath(serviceProperties.getService())
.build(false)
.toUriString();
Edit: вот что я сделал для списка допустимых суффиксов сервера ..
private List<String> validCasServerHostEndings;
@Value("${cas.valid.server.suffixes:company.com,localhost}")
private void setValidCasServerHostEndings(String endings){
validCasServerHostEndings = new ArrayList<>();
for (String ending : StringUtils.split(endings, ",")) {
if (StringUtils.isNotBlank(ending)){
validCasServerHostEndings.add(StringUtils.trim(ending));
}
}
}
private String makeDynamicUrlFromRequest(ServiceProperties serviceProperties){
UriComponents url = UriComponentsBuilder.fromHttpUrl(
linkTo(methodOn(ExposedRestResource.class)
.aMethodOnThatResource(null)).withSelfRel().getHref())
.replacePath(serviceProperties.getService())
.build(false);
boolean valid = false;
for (String validCasServerHostEnding : validCasServerHostEndings) {
if (url.getHost().endsWith(validCasServerHostEnding)){
valid = true;
break;
}
}
if (!valid){
throw new AccessDeniedException("The server is unable to authenticate the requested url.");
}
return url.toString();
}
Я пользуюсь весной 3; обратите внимание на ссылку на весеннюю безопасность. 3 docs –
Возможно, [эта ссылка] (https://jira.springsource.org/browse/SEC-1374) связана и дает некоторое представление о ваших требованиях/проблемах? – Raghuram
Ну, я, конечно, кое-что узнал и устранил одно возможное решение. Поскольку я не могу полагаться на HTTP-запрос, я все равно хотел бы установить службу через некоторые производные значения во время развертывания, которые должны быть безопасными. –