diff --git a/gui/admin-gui/pom.xml b/gui/admin-gui/pom.xml
index 559156372b3..1fa667be097 100644
--- a/gui/admin-gui/pom.xml
+++ b/gui/admin-gui/pom.xml
@@ -220,6 +220,16 @@
2.5.3
runtime
+
+ org.springframework.security
+ spring-security-cas
+ ${spring.security.version}
+
+
+ org.jasig.cas.client
+ cas-client-core
+ 3.5.0
+
org.webjars
webjars-locator-core
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/boot/CasSecurityConfig.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/boot/CasSecurityConfig.java
index 5bacbbfe681..707715d4568 100644
--- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/boot/CasSecurityConfig.java
+++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/boot/CasSecurityConfig.java
@@ -16,8 +16,20 @@
package com.evolveum.midpoint.web.boot;
+import org.apache.commons.lang3.StringUtils;
+import org.jasig.cas.client.validation.TicketValidator;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.cas.ServiceProperties;
+import org.springframework.security.cas.authentication.CasAuthenticationProvider;
+import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
+import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
+import org.springframework.security.core.userdetails.UserDetailsService;
+
+import java.lang.reflect.Constructor;
/**
* Created by Viliam Repan (lazyman).
@@ -26,5 +38,51 @@
@Configuration
public class CasSecurityConfig {
- // TODO move configuration from ctx-web-security-cas.xml here
+ @Value("${auth.cas.midpoint.url}")
+ private String casMidpointUrl;
+ @Value("${auth.cas.server.url}")
+ private String casServerUrl;
+ @Value("${auth.cas.ticketValidator}")
+ private String ticketValidator;
+
+ @Bean
+ public ServiceProperties serviceProperties() {
+ ServiceProperties properties = new ServiceProperties();
+ properties.setService(casMidpointUrl + "/login/cas");
+ properties.setSendRenew(false);
+
+ return properties;
+ }
+
+ @Bean
+ public CasAuthenticationEntryPoint authenticationEntryPoint() {
+ CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint();
+ entryPoint.setLoginUrl(casServerUrl + "/login");
+ entryPoint.setServiceProperties(serviceProperties());
+
+ return entryPoint;
+ }
+
+ @Profile("cas")
+ @Bean
+ public AuthenticationProvider midPointAuthenticationProvider(UserDetailsService userDetailsService) throws Exception {
+ CasAuthenticationProvider provider = new CasAuthenticationProvider();
+ provider.setAuthenticationUserDetailsService(new UserDetailsByNameServiceWrapper<>(userDetailsService));
+ provider.setServiceProperties(serviceProperties());
+ provider.setTicketValidator(createTicketValidatorInstance());
+ provider.setKey("CAS_ID");
+
+ return provider;
+ }
+
+ private TicketValidator createTicketValidatorInstance() throws Exception {
+ if (!StringUtils.contains(ticketValidator, "\\.")) {
+ ticketValidator = "org.jasig.cas.client.validation." + ticketValidator;
+ }
+
+ Class type = (Class) Class.forName(ticketValidator);
+ Constructor c = type.getConstructor(String.class);
+
+ return c.newInstance(casServerUrl);
+ }
}
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/boot/WebSecurityConfig.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/boot/WebSecurityConfig.java
index fa207c7d5e6..d2e12f5a3f5 100755
--- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/boot/WebSecurityConfig.java
+++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/boot/WebSecurityConfig.java
@@ -23,44 +23,58 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Profile;
+import org.springframework.context.annotation.*;
import org.springframework.core.annotation.Order;
+import org.springframework.core.env.Environment;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutFilter;
+import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;
+import java.util.Arrays;
+
/**
* Created by Viliam Repan (lazyman).
*/
@Order(SecurityProperties.BASIC_AUTH_ORDER - 1)
@Configuration
-//TODO
-//@EnableGlobalMethodSecurity(securedEnabled = true)
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+ @Autowired
+ private Environment environment;
@Autowired
private AuthenticationProvider authenticationProvider;
+ @Autowired
+ private AuthenticationManager authenticationManager;
+
@Autowired
private MidPointGuiAuthorizationEvaluator accessDecisionManager;
+ @Value("${auth.sso.header:SM_USER}")
+ private String principalRequestHeader;
+
+ @Value("${auth.cas.server.url:}")
+ private String casServerUrl;
+
@Value("${security.enable-csrf:true}")
private boolean csrfEnabled;
@Value("${auth.logout.url:/}")
private String authLogoutUrl;
- @Value("${auth.sso.header:SM_USER}")
- private String principalRequestHeader;
-
+
+ @Profile("!cas")
@Bean
- public WicketLoginUrlAuthenticationEntryPoint wicketAuthenticationEntryPoint() {
+ public AuthenticationEntryPoint authenticationEntryPoint() {
return new WicketLoginUrlAuthenticationEntryPoint("/login");
}
@@ -71,27 +85,15 @@ public MidPointGuiAuthorizationEvaluator accessDecisionManager(SecurityEnforcer
return new MidPointGuiAuthorizationEvaluator(securityEnforcer, securityContextManager, taskManager);
}
- @Profile("sso")
- @Bean
- public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter() throws Exception {
- RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
- filter.setPrincipalRequestHeader(principalRequestHeader);
- filter.setAuthenticationManager(authenticationManager());
-
- getHttp().addFilterBefore(filter, LogoutFilter.class);
-
- return filter;
- }
-
@Override
public void configure(WebSecurity web) throws Exception {
- // Web (SOAP) services
+ // Web (SOAP) services
web.ignoring().antMatchers("/model/**");
web.ignoring().antMatchers("/ws/**");
// REST service
web.ignoring().antMatchers("/rest/**");
-
+
// Special intra-cluster service to download and delete report outputs
web.ignoring().antMatchers("/report");
@@ -139,7 +141,7 @@ protected void configure(HttpSecurity http) throws Exception {
.successHandler(authenticationSuccessHandler()).permitAll();
http.exceptionHandling()
- .authenticationEntryPoint(wicketAuthenticationEntryPoint())
+ .authenticationEntryPoint(authenticationEntryPoint())
.accessDeniedHandler(accessDeniedHandler());
if (!csrfEnabled) {
@@ -147,6 +149,22 @@ protected void configure(HttpSecurity http) throws Exception {
}
http.headers().disable();
+
+ if (Arrays.stream(environment.getActiveProfiles()).anyMatch(p -> p.equalsIgnoreCase("cas"))) {
+ http.addFilterAt(casFilter(), CasAuthenticationFilter.class);
+ http.addFilterBefore(requestSingleLogoutFilter(), LogoutFilter.class);
+// http.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);
+ }
+
+ if (Arrays.stream(environment.getActiveProfiles()).anyMatch(p -> p.equalsIgnoreCase("sso"))) {
+ http.addFilterBefore(requestHeaderAuthenticationFilter(), LogoutFilter.class);
+ }
+ }
+
+ @Bean
+ @Override
+ protected AuthenticationManager authenticationManager() throws Exception {
+ return super.authenticationManager();
}
@Bean
@@ -154,9 +172,10 @@ public MidPointAccessDeniedHandler accessDeniedHandler() {
return new MidPointAccessDeniedHandler();
}
- @Profile({"!ldap", "!cas"})
+ @Profile("default")
+ @Conditional(DefaultProfileOnlyCondition.class)
@Bean
- public AuthenticationProvider authenticationProvider() {
+ public AuthenticationProvider midPointAuthenticationProvider() throws Exception {
return new MidPointAuthenticationProvider();
}
@@ -181,5 +200,57 @@ public AuditedLogoutHandler logoutHandler() {
return handler;
}
+
+ @Profile("sso")
+ @Bean
+ public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter() {
+ RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
+ filter.setPrincipalRequestHeader(principalRequestHeader);
+ filter.setAuthenticationManager(authenticationManager);
+
+ return filter;
+ }
+
+ @Profile("cas")
+ @Bean
+ public CasAuthenticationFilter casFilter() {
+ CasAuthenticationFilter filter = new CasAuthenticationFilter();
+ filter.setAuthenticationManager(authenticationManager);
+
+ return filter;
+ }
+
+ @Profile("cas")
+ @Bean
+ public LogoutFilter requestSingleLogoutFilter() {
+ LogoutFilter filter = new LogoutFilter(casServerUrl + "/logout", new SecurityContextLogoutHandler());
+ filter.setFilterProcessesUrl("/j_spring_cas_security_logout");
+
+ return filter;
+ }
+
+// @Profile("cas")
+// @Bean
+// public SingleSignOutFilter singleSignOutFilter() {
+// SingleSignOutFilter filter = new SingleSignOutFilter();
+// filter.setCasServerUrlPrefix(casServerUrl);
+//
+// return filter;
+// }
+
+ private static class DefaultProfileOnlyCondition implements Condition {
+
+ @Override
+ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
+
+ if (context.getEnvironment() == null) {
+ return true;
+ }
+
+ String[] activeProfiles = context.getEnvironment().getActiveProfiles();
+
+ return !Arrays.stream(activeProfiles).anyMatch(p -> p.equalsIgnoreCase("cas") || p.equalsIgnoreCase("ldap"));
+ }
+ }
}
diff --git a/gui/admin-gui/src/main/resources/application-cas.yml b/gui/admin-gui/src/main/resources/application-cas.yml
deleted file mode 100644
index f232c5f74bc..00000000000
--- a/gui/admin-gui/src/main/resources/application-cas.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-#auth:
-# cas:
-# midpoint:
-# host: http://localhost:8080/midpoint
-# send:
-# renew: false
-# server:
-# host: http://localhost:9090/
\ No newline at end of file
diff --git a/gui/admin-gui/src/main/resources/application-ldap.yml b/gui/admin-gui/src/main/resources/application-ldap.yml
deleted file mode 100644
index 52f6a26e2f2..00000000000
--- a/gui/admin-gui/src/main/resources/application-ldap.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-#auth:
-# ldap:
-# host: ldap://localhost:389/dc=example,dc=com
-# manager: cn=admin,dc=example,dc=com
-# password: secret
-# dn:
-# pattern: uid={0},ou=people
-#
-# search:
-# pattern: (uid={0})
-# subtree: true
\ No newline at end of file
diff --git a/gui/admin-gui/src/main/resources/application.yml b/gui/admin-gui/src/main/resources/application.yml
index d398a995880..03cf6fdb5c5 100644
--- a/gui/admin-gui/src/main/resources/application.yml
+++ b/gui/admin-gui/src/main/resources/application.yml
@@ -20,7 +20,27 @@ server:
auth:
logout:
url: / # NOTE: This URL is relative to application root
-
+## Example SSO header authentication configuration
+# sso:
+# header: SM_USER
+## Example CAS SSO configuration
+# cas:
+# midpoint:
+# url: http://localhost:38080/midpoint
+# server:
+# url: http://localhost:8080/cas
+# ticketValidator: Cas30ServiceTicketValidator
+## Example LDAP authentication configuration
+# ldap:
+# host: ldap://localhost:389/dc=example,dc=com
+# manager: cn=admin,dc=example,dc=com
+# password: secret
+# dn:
+# pattern: uid={0},ou=people
+#
+# search:
+# pattern: (uid={0})
+# subtree: true
#security:
# enable-csrf: false # default for midpoint is true