Ich weiß, das ist ein bisschen alt, aber ich hatte gerade genau dieses Problem zu lösen, und nicht wirklich etwas in den neueren Stapeln finden kann.
Wir haben mehrere Umgebungen, die den gleichen CAS-Dienst teilen (think dev, qa, uat und lokale Entwicklungsumgebungen); Wir haben die Möglichkeit, jede Umgebung von mehr als einer URL aus zu erreichen (über den Client-seitigen Webserver über einen Reverse-Proxy und direkt zum Back-End-Server selbst). Dies bedeutet, dass die Angabe einer einzelnen URL bestenfalls schwierig ist. Vielleicht gibt es einen Weg, dies zu tun, aber in der Lage, eine dynamische ServiceProperties.getService()
zu verwenden. Ich werde wahrscheinlich eine Art Server-Suffix-Prüfung hinzufügen, um sicherzustellen, dass die URL irgendwann nicht entführt wird.
Hier ist, was ich getan habe, unabhängig von der die gesicherten Ressource für den Zugriff auf URL arbeiten, um den Grund CAS Fluss zu bekommen ...
- Aufschalten die
CasAuthenticationFilter
.
- Überschreiben Sie die
CasAuthenticationProvider
.
setAuthenticateAllArtifacts(true)
über die ServiceProperties
.
Hier ist die lange Form meiner Feder Konfigurations-Bean:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
public class CasSecurityConfiguration extends WebSecurityConfigurerAdapter {
Nur die übliche Federkonfiguration Bohne.
@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;
Einige externe Konfigurationsparameter.
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(casValidationUri);
serviceProperties.setSendRenew(false);
serviceProperties.setAuthenticateAllArtifacts(true);
return serviceProperties;
}
Der Schlüssel oben ist der setAuthenticateAllArtifacts(true)
Aufruf. Dies wird der Service-Ticket-Validator die AuthenticationDetailsSource
Implementierung eher als ein hartcodierte ServiceProperties.getService()
Anruf
@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
return new Cas20ServiceTicketValidator(casServerUrl);
}
Standard-Ticket-Validator ..
@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);
}
};
}
Standard-Haken zu einem bestehenden UserDetailsService verwenden macht
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(authenticationUserDetailsService());
casAuthenticationProvider.setServiceProperties(serviceProperties());
casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setKey(casProviderKey);
return casAuthenticationProvider;
}
Standardauthentifizierungsanbieter
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setServiceProperties(serviceProperties());
casAuthenticationFilter.setAuthenticationDetailsSource(dynamicServiceResolver());
return casAuthenticationFilter;
}
Key ist hier die dynamicServiceResolver()
Einstellung ..
@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;
}
};
}
};
}
dynamisch Service URL aus der makeDynamicUrlFromRequest()
Methode erstellt. Dieses Bit wird bei der Ticketvalidierung verwendet.
@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;
}
Dieser Teil verwendet denselben dynamischen URL-Ersteller, wenn CAS zum Anmeldebildschirm umleiten möchte.
private String makeDynamicUrlFromRequest(ServiceProperties serviceProperties){
return "https://howeverYouBuildYourOwnDynamicUrl.com";
}
Das ist was auch immer Sie daraus machen. Ich habe nur die ServiceProperties übergeben, um den URI des Dienstes zu speichern, für den wir konfiguriert sind. Wir verwenden HATEAOS auf der Rückseite und haben eine Implementierung wie:
return UriComponentsBuilder.fromHttpUrl(
linkTo(methodOn(ExposedRestResource.class)
.aMethodOnThatResource(null)).withSelfRel().getHref())
.replacePath(serviceProperties.getService())
.build(false)
.toUriString();
Edit: hier ist das, was ich für die Liste der gültigen Server-Suffixe haben ..
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();
}
Ich verwende Feder 3; notieren Sie den Link zum Frühling Sicherheit 3 Dokumente –
Vielleicht ist [dieser Link] (https://jira.springsource.org/browse/SEC-1374) verwandt und gibt einige Einblicke in Ihre Anforderung/Problem? – Raghuram
Nun, ich habe sicherlich etwas gelernt und eine mögliche Lösung beseitigt. Da ich mich nicht auf die HTTP-Anfrage verlassen kann, möchte ich den Dienst dennoch über einige abgeleitete Werte zur Bereitstellungszeit festlegen, die sicher sein sollte. –