You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by sh...@apache.org on 2015/12/11 10:33:16 UTC

kylin git commit: KYLIN-1219 support SSO with Spring SAML

Repository: kylin
Updated Branches:
  refs/heads/2.x-staging 82258382d -> 9ba89b886


KYLIN-1219 support SSO with Spring SAML


Project: http://git-wip-us.apache.org/repos/asf/kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/9ba89b88
Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/9ba89b88
Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/9ba89b88

Branch: refs/heads/2.x-staging
Commit: 9ba89b88679ac9e543d1e85f955ad63e8192f9cc
Parents: 8225838
Author: shaofengshi <sh...@apache.org>
Authored: Fri Dec 11 17:32:18 2015 +0800
Committer: shaofengshi <sh...@apache.org>
Committed: Fri Dec 11 17:33:01 2015 +0800

----------------------------------------------------------------------
 build/bin/kylin.sh                              |   9 +-
 build/conf/kylin.properties                     |  37 +-
 .../test_case_data/localmeta/kylin.properties   |   4 +-
 .../test_case_data/sandbox/kylin.properties     |   4 +-
 pom.xml                                         |   2 +
 server/pom.xml                                  |  28 ++
 .../security/KylinAuthenticationProvider.java   | 101 +++++
 .../kylin/rest/security/LdapProvider.java       |   1 +
 .../rest/security/SAMLUserDetailsService.java   |  32 ++
 .../src/main/resources/applicationContext.xml   |   6 +-
 .../resources/kylin-server-log4j.properties     |   5 +
 server/src/main/resources/kylinSecurity.xml     | 452 ++++++++++++++++---
 12 files changed, 586 insertions(+), 95 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kylin/blob/9ba89b88/build/bin/kylin.sh
----------------------------------------------------------------------
diff --git a/build/bin/kylin.sh b/build/bin/kylin.sh
index 9e91131..50c5ce2 100644
--- a/build/bin/kylin.sh
+++ b/build/bin/kylin.sh
@@ -49,11 +49,7 @@ then
 
 
 
-    useSandbox=`sh ${dir}/get-properties.sh kylin.sandbox`
-    spring_profile="default"
-    if [ "$useSandbox" = "true" ]
-        then spring_profile="sandbox"
-    fi
+    spring_profile=`sh ${dir}/get-properties.sh kylin.security.profile`
 
     #retrive $hive_dependency and $hbase_dependency
     source ${dir}/find-hive-dependency.sh
@@ -64,7 +60,8 @@ then
     fi
 
     export HBASE_CLASSPATH_PREFIX=${tomcat_root}/bin/bootstrap.jar:${tomcat_root}/bin/tomcat-juli.jar:${tomcat_root}/lib/*:$HBASE_CLASSPATH_PREFIX
-    export HBASE_CLASSPATH=$hive_dependency:${HBASE_CLASSPATH}
+    mkdir -p ${KYLIN_HOME}/ext
+    export HBASE_CLASSPATH=$hive_dependency:${KYLIN_HOME}/lib/*:${KYLIN_HOME}/ext/*:${HBASE_CLASSPATH}
 
     #debug if encounter NoClassDefError
     #hbase classpath

http://git-wip-us.apache.org/repos/asf/kylin/blob/9ba89b88/build/conf/kylin.properties
----------------------------------------------------------------------
diff --git a/build/conf/kylin.properties b/build/conf/kylin.properties
index cc91824..36f34a7 100644
--- a/build/conf/kylin.properties
+++ b/build/conf/kylin.properties
@@ -60,19 +60,42 @@ kylin.hbase.region.cut.small=5
 kylin.hbase.region.cut.medium=10
 kylin.hbase.region.cut.large=50
 
-## Config for Restful APP ##
-# database connection settings:
-ldap.server=
+
+## kylin security configurations
+
+# spring security profile, options: testing, ldap, saml
+# with "testing" profile, user can use pre-defined name/pwd like KYLIN/ADMIN to login
+kylin.security.profile=testing
+
+# default roles and admin roles in LDAP, for ldap and saml
+acl.defaultRole=ROLE_ANALYST,ROLE_MODELER
+acl.adminRole=ROLE_ADMIN
+
+#LDAP authentication configuration
+ldap.server=ldap://ldap_server:389
 ldap.username=
 ldap.password=
+
+#LDAP user account directory; 
 ldap.user.searchBase=
 ldap.user.searchPattern=
 ldap.user.groupSearchBase=
-ldap.service.searchBase=OU=
+
+#LDAP service account directory
+ldap.service.searchBase=
 ldap.service.searchPattern=
 ldap.service.groupSearchBase=
-acl.adminRole=
-acl.defaultRole=
+
+#SAML configurations for SSO
+# SAML IDP metadata file location
+saml.metadata.file=classpath:sso_metadata.xml
+saml.metadata.entityBaseURL=https://hostname/kylin
+saml.context.scheme=https
+saml.context.serverName=hostname
+saml.context.serverPort=443
+saml.context.contextPath=/kylin
+
+
 ganglia.group=
 ganglia.port=8664
 
@@ -105,5 +128,5 @@ kylin.web.contact_mail=
 #env DEV|QA|PROD
 deploy.env=DEV
 
-###########################config info for sandbox#######################
+###########################deprecated configs#######################
 kylin.sandbox=true

http://git-wip-us.apache.org/repos/asf/kylin/blob/9ba89b88/examples/test_case_data/localmeta/kylin.properties
----------------------------------------------------------------------
diff --git a/examples/test_case_data/localmeta/kylin.properties b/examples/test_case_data/localmeta/kylin.properties
index 48f01f5..a008494 100644
--- a/examples/test_case_data/localmeta/kylin.properties
+++ b/examples/test_case_data/localmeta/kylin.properties
@@ -40,7 +40,7 @@ kylin.job.yarn.app.rest.check.interval.seconds=10
 kylin.hbase.default.compression.codec=gzip
 
 
-
+kylin.security.profile=testing
 ## Config for Restful APP ##
 # database connection settings:
 ldap.server=
@@ -57,7 +57,5 @@ acl.defaultRole=
 ganglia.group=
 ganglia.port=8664
 
-###########################config info for sandbox#######################
-kylin.sandbox=true
 
 

http://git-wip-us.apache.org/repos/asf/kylin/blob/9ba89b88/examples/test_case_data/sandbox/kylin.properties
----------------------------------------------------------------------
diff --git a/examples/test_case_data/sandbox/kylin.properties b/examples/test_case_data/sandbox/kylin.properties
index 35e2927..a12bc40 100644
--- a/examples/test_case_data/sandbox/kylin.properties
+++ b/examples/test_case_data/sandbox/kylin.properties
@@ -51,6 +51,8 @@ kylin.job.yarn.app.rest.check.interval.seconds=10
 #default compression codec for htable,snappy,lzo,gzip,lz4
 kylin.hbase.default.compression.codec=gzip
 
+kylin.security.profile=testing
+
 ## Config for Restful APP ##
 # database connection settings:
 ldap.server=
@@ -96,6 +98,4 @@ kylin.web.contact_mail=
 #env DEV|QA|PROD
 deploy.env=DEV
 
-###########################config info for sandbox#######################
-kylin.sandbox=true
 

http://git-wip-us.apache.org/repos/asf/kylin/blob/9ba89b88/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 82dc06b..28ab8d7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,6 +92,8 @@
 
         <!-- REST Service -->
         <spring.framework.version>3.1.2.RELEASE</spring.framework.version>
+        <spring.framework.security.extensions.version>1.0.1.RELEASE</spring.framework.security.extensions.version>
+        <opensaml.version>2.6.1</opensaml.version>
         <spring.boot.version>1.2.7.RELEASE</spring.boot.version>
 
         <!-- Calcite Version -->

http://git-wip-us.apache.org/repos/asf/kylin/blob/9ba89b88/server/pom.xml
----------------------------------------------------------------------
diff --git a/server/pom.xml b/server/pom.xml
index 304bb73..eeb37f7 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -204,6 +204,34 @@
             <version>${spring.framework.version}</version>
         </dependency>
         <dependency>
+            <groupId>org.springframework.security.extensions</groupId>
+            <artifactId>spring-security-saml2-core</artifactId>
+            <version>${spring.framework.security.extensions.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opensaml</groupId>
+            <artifactId>opensaml</artifactId>
+            <version>${opensaml.version}</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>xml-apis</artifactId>
+                    <groupId>org.apache.xerces</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>jcl-over-slf4j</artifactId>
+                    <groupId>org.slf4j</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>serializer</artifactId>
+                    <groupId>org.apache.xerces</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>log4j-over-slf4j</artifactId>
+                    <groupId>org.slf4j</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
             <groupId>net.sf.ehcache</groupId>
             <artifactId>ehcache</artifactId>
             <version>${ehcache.version}</version>

http://git-wip-us.apache.org/repos/asf/kylin/blob/9ba89b88/server/src/main/java/org/apache/kylin/rest/security/KylinAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/security/KylinAuthenticationProvider.java b/server/src/main/java/org/apache/kylin/rest/security/KylinAuthenticationProvider.java
new file mode 100644
index 0000000..be28bdd
--- /dev/null
+++ b/server/src/main/java/org/apache/kylin/rest/security/KylinAuthenticationProvider.java
@@ -0,0 +1,101 @@
+package org.apache.kylin.rest.security;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+import org.apache.kylin.rest.service.UserService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.saml.SAMLAuthenticationProvider;
+import org.springframework.util.Assert;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/**
+ * A wrapper class for the authentication provider; Will do something more for Kylin.
+ */
+public class KylinAuthenticationProvider implements AuthenticationProvider {
+
+    private static final Logger logger = LoggerFactory.getLogger(KylinAuthenticationProvider.class);
+
+    @Autowired
+    UserService userService;
+
+    @Autowired
+    private CacheManager cacheManager;
+
+    //Embedded authentication provider
+    private AuthenticationProvider authenticationProvider;
+
+    MessageDigest md = null;
+    
+    public KylinAuthenticationProvider(AuthenticationProvider authenticationProvider) {
+        super();
+        Assert.notNull(authenticationProvider, "The embedded authenticationProvider should not be null.");
+        this.authenticationProvider = authenticationProvider;
+        try {
+            md = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("Failed to init Message Digest ", e);
+        }
+    }
+    @Override
+    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+        Authentication authed = null;
+        Cache userCache = cacheManager.getCache("UserCache");
+        md.reset();
+        byte[] hashKey = md.digest((authentication.getName() + authentication.getCredentials()).getBytes());
+        String userKey = Arrays.toString(hashKey);
+
+        Element authedUser = userCache.get(userKey);
+        if (null != authedUser) {
+            authed = (Authentication) authedUser.getObjectValue();
+            SecurityContextHolder.getContext().setAuthentication(authed);
+        } else {
+            try {
+                authed = authenticationProvider.authenticate(authentication);
+                userCache.put(new Element(userKey, authed));
+            } catch (AuthenticationException e) {
+                logger.error("Failed to auth user: " + authentication.getName(), e);
+                throw e;
+            }
+
+            logger.debug("Authenticated user " + authed.toString());
+            
+            UserDetails user = (UserDetails)authed.getDetails();
+            Assert.notNull(user, "The UserDetail is null.");
+
+            logger.debug("User authorities :" + user.getAuthorities());
+            if (!userService.userExists(user.getUsername())) {
+                userService.createUser(user);
+            } else {
+                userService.updateUser(user);
+            }
+        }
+
+        return authed;
+    }
+
+    @Override
+    public boolean supports(Class<?> authentication) {
+        return authenticationProvider.supports(authentication);
+    }
+
+    public AuthenticationProvider getAuthenticationProvider() {
+        return authenticationProvider;
+    }
+
+    public void setAuthenticationProvider(AuthenticationProvider authenticationProvider) {
+        this.authenticationProvider = authenticationProvider;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/9ba89b88/server/src/main/java/org/apache/kylin/rest/security/LdapProvider.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/security/LdapProvider.java b/server/src/main/java/org/apache/kylin/rest/security/LdapProvider.java
index b34a2bd..2dae90b 100644
--- a/server/src/main/java/org/apache/kylin/rest/security/LdapProvider.java
+++ b/server/src/main/java/org/apache/kylin/rest/security/LdapProvider.java
@@ -41,6 +41,7 @@ import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
 
 /**
  * @author xduo
+ * @deprecated replaced by KylinAuthenticationProvider
  * 
  */
 public class LdapProvider extends LdapAuthenticationProvider {

http://git-wip-us.apache.org/repos/asf/kylin/blob/9ba89b88/server/src/main/java/org/apache/kylin/rest/security/SAMLUserDetailsService.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/security/SAMLUserDetailsService.java b/server/src/main/java/org/apache/kylin/rest/security/SAMLUserDetailsService.java
new file mode 100644
index 0000000..8d13805
--- /dev/null
+++ b/server/src/main/java/org/apache/kylin/rest/security/SAMLUserDetailsService.java
@@ -0,0 +1,32 @@
+package org.apache.kylin.rest.security;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.ldap.userdetails.LdapUserDetailsService;
+import org.springframework.security.saml.SAMLCredential;
+
+/**
+ * An implementation of SAMLUserDetailsService by delegating the query to LdapUserDetailsService.
+ */
+public class SAMLUserDetailsService implements org.springframework.security.saml.userdetails.SAMLUserDetailsService {
+
+    private static final Logger logger = LoggerFactory.getLogger(SAMLUserDetailsService.class);
+    private LdapUserDetailsService ldapUserDetailsService;
+
+    public SAMLUserDetailsService(LdapUserDetailsService ldapUserDetailsService) {
+        this.ldapUserDetailsService = ldapUserDetailsService;
+    }
+
+    @Override
+    public Object loadUserBySAML(SAMLCredential samlCredential) throws UsernameNotFoundException {
+        final String userEmail = samlCredential.getAttributeAsString("email");
+        logger.debug("samlCredential.email:" + userEmail);
+        final String userName = userEmail.substring(0, userEmail.indexOf("@"));
+
+        UserDetails userDetails = ldapUserDetailsService.loadUserByUsername(userName);
+        logger.debug("userDeail by search ldap with '" + userName + "' is: " + userDetails);
+        return userDetails;
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/9ba89b88/server/src/main/resources/applicationContext.xml
----------------------------------------------------------------------
diff --git a/server/src/main/resources/applicationContext.xml b/server/src/main/resources/applicationContext.xml
index a103b56..dd66070 100644
--- a/server/src/main/resources/applicationContext.xml
+++ b/server/src/main/resources/applicationContext.xml
@@ -85,19 +85,19 @@
 
     <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
           p:cacheManager-ref="ehcache"/>
-    <beans profile="default">
+    <beans profile="ldap,saml">
         <bean id="ehcache"
               class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
               p:configLocation="classpath:ehcache.xml" p:shared="true"/>
     </beans>
-    <beans profile="sandbox,testing">
+    <beans profile="testing">
         <bean id="ehcache"
               class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
               p:configLocation="classpath:ehcache-test.xml" p:shared="true"/>
     </beans>
 
     <!-- hbase storage/global lock Config -->
-    <beans profile="default,sandbox">
+    <beans profile="ldap,saml">
         <bean id="aclHBaseStorage" class="org.apache.kylin.rest.security.RealAclHBaseStorage"/>
         <bean id="jobLock" class="org.apache.kylin.storage.hbase.util.ZookeeperJobLock"/>
     </beans>

http://git-wip-us.apache.org/repos/asf/kylin/blob/9ba89b88/server/src/main/resources/kylin-server-log4j.properties
----------------------------------------------------------------------
diff --git a/server/src/main/resources/kylin-server-log4j.properties b/server/src/main/resources/kylin-server-log4j.properties
index a93627a..f4df80d 100644
--- a/server/src/main/resources/kylin-server-log4j.properties
+++ b/server/src/main/resources/kylin-server-log4j.properties
@@ -49,3 +49,8 @@ log4j.logger.org.apache.kylin.query=DEBUG, query
 log4j.logger.org.apache.kylin.rest.controller.JobController=DEBUG, job
 log4j.logger.org.apache.kylin.rest.service.JobService=DEBUG, job
 log4j.logger.org.apache.kylin.job=DEBUG, job
+
+#spring security config
+log4j.logger.org.springframework.security=INFO,file
+log4j.logger.org.opensaml=INFO,file
+log4j.logger.PROTOCOL_MESSAGE=INFO,file

http://git-wip-us.apache.org/repos/asf/kylin/blob/9ba89b88/server/src/main/resources/kylinSecurity.xml
----------------------------------------------------------------------
diff --git a/server/src/main/resources/kylinSecurity.xml b/server/src/main/resources/kylinSecurity.xml
index ee3c891..3b2125a 100644
--- a/server/src/main/resources/kylinSecurity.xml
+++ b/server/src/main/resources/kylinSecurity.xml
@@ -1,39 +1,16 @@
-<beans xmlns="http://www.springframework.org/schema/beans" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:scr="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:tx="http://www.springframework.org/schema/tx"
+	   xmlns:scr="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	   xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans
 	http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
 	http://www.springframework.org/schema/security
 	http://www.springframework.org/schema/security/spring-security-3.1.xsd
 	http://www.springframework.org/schema/tx
-    http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
+    http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
 
 	<scr:global-method-security pre-post-annotations="enabled">
 		<scr:expression-handler ref="expressionHandler" />
 	</scr:global-method-security>
 
-	<scr:http auto-config="true" use-expressions="true">
-		<scr:http-basic entry-point-ref="unauthorisedEntryPoint" />
-
-		<scr:intercept-url pattern="/api/user/authentication*/**" access="permitAll" />
-		<scr:intercept-url pattern="/api/query*/**" access="isAuthenticated()" />
-		<scr:intercept-url pattern="/api/metadata*/**" access="isAuthenticated()" />
-		<scr:intercept-url pattern="/api/**/metrics" access="permitAll" />
-        <scr:intercept-url pattern="/api/cache*/**" access="permitAll" />
-		<scr:intercept-url pattern="/api/cubes/src/tables" access="hasAnyRole('ROLE_ANALYST')" />
-		<scr:intercept-url pattern="/api/cubes*/**" access="isAuthenticated()" />
-		<scr:intercept-url pattern="/api/models*/**" access="isAuthenticated()" />
-		<scr:intercept-url pattern="/api/streaming*/**" access="isAuthenticated()" />
-		<scr:intercept-url pattern="/api/job*/**" access="isAuthenticated()" />
-		<scr:intercept-url pattern="/api/admin/config" access="permitAll" />
-		<scr:intercept-url pattern="/api/projects" access="permitAll" />
-		<scr:intercept-url pattern="/api/admin*/**" access="hasRole('ROLE_ADMIN')" />
-		<scr:intercept-url pattern="/api/**" access="isAuthenticated()" />
-
-		<scr:logout invalidate-session="true" delete-cookies="JSESSIONID" />
-		<scr:session-management session-fixation-protection="newSession" />
-	</scr:http>
-	
-	<!-- user auth -->
-	<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
-
 	<!-- acl config -->
 	<bean id="aclPermissionFactory" class="org.apache.kylin.rest.security.AclPermissionFactory" />
 
@@ -45,6 +22,12 @@
 		<constructor-arg ref="aclService" />
 		<property name="permissionFactory" ref="aclPermissionFactory" />
 	</bean>
+
+	<bean id="ldapSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
+		<constructor-arg value="${ldap.server}" />
+		<property name="userDn" value="${ldap.username}" />
+		<property name="password" value="${ldap.password}" />
+	</bean>
 	
 	<bean id="aclAuthorizationStrategy"
 		class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
@@ -70,72 +53,76 @@
 		<constructor-arg ref="auditLogger" />
 	</bean>
 	
-	<beans profile="default">
-		<bean id="ldapUserAuthProvider" class="org.apache.kylin.rest.security.LdapProvider">
+	<beans profile="ldap">
+		<bean id="kylinUserAuthProvider" class="org.apache.kylin.rest.security.KylinAuthenticationProvider">
 			<constructor-arg>
-				<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
-					<constructor-arg ref="ldapSource" />
-					<property name="userSearch">
-						<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
-							<constructor-arg index="0" value="${ldap.user.searchBase}" />
-							<constructor-arg index="1" value="${ldap.user.searchPattern}" />
-							<constructor-arg index="2" ref="ldapSource" />
+				<bean id="ldapUserAuthenticationProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
+					<constructor-arg>
+						<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
+							<constructor-arg ref="ldapSource" />
+							<property name="userSearch">
+								<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
+									<constructor-arg index="0" value="${ldap.user.searchBase}" />
+									<constructor-arg index="1" value="${ldap.user.searchPattern}" />
+									<constructor-arg index="2" ref="ldapSource" />
+								</bean>
+							</property>
 						</bean>
-					</property>
-				</bean>
-			</constructor-arg>
-			<constructor-arg>
-				<bean class="org.apache.kylin.rest.security.AuthoritiesPopulator">
-					<constructor-arg index="0" ref="ldapSource" />
-					<constructor-arg index="1" value="${ldap.user.groupSearchBase}" />
-					<constructor-arg index="2" value="${acl.adminRole}" />
-					<constructor-arg index="3" value="${acl.defaultRole}" />
+					</constructor-arg>
+					<constructor-arg>
+						<bean class="org.apache.kylin.rest.security.AuthoritiesPopulator">
+							<constructor-arg index="0" ref="ldapSource" />
+							<constructor-arg index="1" value="${ldap.user.groupSearchBase}" />
+							<constructor-arg index="2" value="${acl.adminRole}" />
+							<constructor-arg index="3" value="${acl.defaultRole}" />
+						</bean>
+					</constructor-arg>
 				</bean>
 			</constructor-arg>
 		</bean>
 
-		<bean id="ldapServiceAccountAuthProvider" class="org.apache.kylin.rest.security.LdapProvider">
+		<bean id="kylinServiceAccountAuthProvider" class="org.apache.kylin.rest.security.KylinAuthenticationProvider">
 			<constructor-arg>
-				<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
-					<constructor-arg ref="ldapSource" />
-					<property name="userSearch">
-						<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
-							<constructor-arg index="0" value="${ldap.service.searchBase}" />
-							<constructor-arg index="1" value="${ldap.service.searchPattern}" />
-							<constructor-arg index="2" ref="ldapSource" />
+				<bean id="ldapServiceAuthenticationProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
+					<constructor-arg>
+						<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
+							<constructor-arg ref="ldapSource" />
+							<property name="userSearch">
+								<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
+									<constructor-arg index="0" value="${ldap.service.searchBase}" />
+									<constructor-arg index="1" value="${ldap.service.searchPattern}" />
+									<constructor-arg index="2" ref="ldapSource" />
+								</bean>
+							</property>
 						</bean>
-					</property>
-				</bean>
-			</constructor-arg>
-			<constructor-arg>
-				<bean class="org.apache.kylin.rest.security.AuthoritiesPopulator">
-					<constructor-arg index="0" ref="ldapSource" />
-					<constructor-arg index="1" value="${ldap.service.groupSearchBase}" />
-					<constructor-arg index="2" value="${acl.adminRole}" />
-					<constructor-arg index="3" value="${acl.defaultRole}" />
+					</constructor-arg>
+					<constructor-arg>
+						<bean class="org.apache.kylin.rest.security.AuthoritiesPopulator">
+							<constructor-arg index="0" ref="ldapSource" />
+							<constructor-arg index="1" value="${ldap.service.groupSearchBase}" />
+							<constructor-arg index="2" value="${acl.adminRole}" />
+							<constructor-arg index="3" value="${acl.defaultRole}" />
+						</bean>
+					</constructor-arg>
 				</bean>
 			</constructor-arg>
 		</bean>
 
-		<scr:authentication-manager alias="authenticationManager">
+		<scr:authentication-manager alias="ldapAuthenticationManager">
 			<!-- do user ldap auth -->
-			<scr:authentication-provider ref="ldapUserAuthProvider"></scr:authentication-provider>
+			<scr:authentication-provider ref="kylinUserAuthProvider"></scr:authentication-provider>
 
 			<!-- do service account ldap auth -->
-			<scr:authentication-provider ref="ldapServiceAccountAuthProvider"></scr:authentication-provider>
-
-			<!-- custom user provider <authentication-provider user-service-ref="userService"> <password-encoder ref="passwordEncoder" /> </authentication-provider> -->
+			<scr:authentication-provider ref="kylinServiceAccountAuthProvider"></scr:authentication-provider>
 		</scr:authentication-manager>
 
-		<bean id="ldapSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
-			<constructor-arg value="${ldap.server}" />
-			<property name="userDn" value="${ldap.username}" />
-			<property name="password" value="${ldap.password}" />
-		</bean>
 	</beans>
 
-	<beans profile="sandbox,testing">
-		<scr:authentication-manager alias="authenticationManager">
+	<beans profile="testing">
+		<!-- user auth -->
+		<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
+		
+		<scr:authentication-manager alias="testingAuthenticationManager">
 			<scr:authentication-provider>
 				<scr:user-service>
 					<scr:user name="MODELER" password="$2a$10$Le5ernTeGNIARwMJsY0WaOLioNQdb0QD11DwjeyNqqNRp5NaDo2FG" authorities="ROLE_MODELER" />
@@ -146,4 +133,321 @@
 			</scr:authentication-provider>
 		</scr:authentication-manager>
 	</beans>
+	
+	<beans profile="testing,ldap">
+		<scr:http auto-config="true" use-expressions="true">
+			<scr:http-basic entry-point-ref="unauthorisedEntryPoint" />
+
+			<scr:intercept-url pattern="/api/user/authentication*/**" access="permitAll" />
+			<scr:intercept-url pattern="/api/query*/**" access="isAuthenticated()" />
+			<scr:intercept-url pattern="/api/metadata*/**" access="isAuthenticated()" />
+			<scr:intercept-url pattern="/api/**/metrics" access="permitAll" />
+			<scr:intercept-url pattern="/api/cache*/**" access="permitAll" />
+			<scr:intercept-url pattern="/api/cubes/src/tables" access="hasAnyRole('ROLE_ANALYST')" />
+			<scr:intercept-url pattern="/api/cubes*/**" access="isAuthenticated()" />
+			<scr:intercept-url pattern="/api/models*/**" access="isAuthenticated()" />
+			<scr:intercept-url pattern="/api/streaming*/**" access="isAuthenticated()" />
+			<scr:intercept-url pattern="/api/job*/**" access="isAuthenticated()" />
+			<scr:intercept-url pattern="/api/admin/config" access="permitAll" />
+			<scr:intercept-url pattern="/api/projects" access="permitAll" />
+			<scr:intercept-url pattern="/api/admin*/**" access="hasRole('ROLE_ADMIN')" />
+			<scr:intercept-url pattern="/api/**" access="isAuthenticated()" />
+
+			<scr:logout invalidate-session="true" delete-cookies="JSESSIONID" />
+			<scr:session-management session-fixation-protection="newSession" />
+		</scr:http>
+	</beans>
+
+	<beans profile="saml">
+		<!-- Enable auto-wiring -->
+		<context:annotation-config/>
+
+		<!-- Scan for auto-wiring classes in spring saml packages -->
+		<context:component-scan base-package="org.springframework.security.saml"/>
+
+		<!-- Unsecured pages -->
+		<scr:http security="none" pattern="/images/**"/>
+		<scr:http security="none" pattern="/css/**"/>
+		<scr:http security="none" pattern="/fonts/**"/>
+		<scr:http security="none" pattern="/js/**"/>
+		<scr:http security="none" pattern="/login/**"/>
+		<scr:http security="none" pattern="/api/projects" />
+
+		<!-- Secured pages with SAML as entry point -->
+		<scr:http entry-point-ref="samlEntryPoint" use-expressions="false">
+			<scr:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
+			<scr:custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
+			<scr:custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/>
+		</scr:http>
+
+		<!-- Central storage of cryptographic keys -->
+		<bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
+			<constructor-arg value="classpath:samlKeystore.jks"/>
+			<constructor-arg type="java.lang.String" value="changeit"/>
+			<constructor-arg>
+				<map>
+					<entry key="kylin" value="changeit"/>
+				</map>
+			</constructor-arg>
+			<constructor-arg type="java.lang.String" value="kylin"/>
+		</bean>
+
+		<!-- Filters for processing of SAML messages -->
+		<bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy">
+			<scr:filter-chain-map request-matcher="ant">
+				<scr:filter-chain pattern="/saml/login/**" filters="samlEntryPoint"/>
+				<scr:filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter"/>
+				<scr:filter-chain pattern="/saml/metadata/**" filters="metadataDisplayFilter"/>
+				<scr:filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter"/>
+				<scr:filter-chain pattern="/saml/SSOHoK/**" filters="samlWebSSOHoKProcessingFilter"/>
+				<scr:filter-chain pattern="/saml/SingleLogout/**" filters="samlLogoutProcessingFilter"/>
+			</scr:filter-chain-map>
+		</bean>
+
+		<!-- Handler deciding where to redirect user after successful login -->
+		<bean id="successRedirectHandler"
+			  class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
+			<property name="defaultTargetUrl" value="/models"/>
+		</bean>
+
+		<!-- Handler deciding where to redirect user after failed login -->
+		<bean id="failureRedirectHandler"
+			  class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
+			<property name="useForward" value="true"/>
+			<property name="defaultFailureUrl" value="/login"/>
+		</bean>
+
+		<!-- Handler for successful logout -->
+		<bean id="successLogoutHandler" class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
+			<property name="defaultTargetUrl" value="/login"/>
+		</bean>
+
+		<scr:authentication-manager alias="samlAuthenticationManager">
+			<!-- Register authentication manager for SAML provider -->
+			<scr:authentication-provider ref="kylinAuthenticationProvider"/>
+		</scr:authentication-manager>
+
+		<!-- Logger for SAML messages and events -->
+		<bean id="samlLogger" class="org.springframework.security.saml.log.SAMLDefaultLogger"/>
+
+		<!-- Filter automatically generates default SP metadata -->
+		<bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
+			<constructor-arg>
+				<bean class="org.springframework.security.saml.metadata.MetadataGenerator">
+					<property name="extendedMetadata">
+						<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
+							<property name="idpDiscoveryEnabled" value="false"/>
+						</bean>
+					</property>
+					<property name="entityBaseURL" value = "${saml.metadata.entityBaseURL}"/>
+				</bean>
+			</constructor-arg>
+		</bean>
+
+		<!-- Entry point to initialize authentication, default values taken from properties file -->
+		<bean id="samlEntryPoint" class="org.springframework.security.saml.SAMLEntryPoint">
+			<property name="defaultProfileOptions">
+				<bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
+					<property name="includeScoping" value="false"/>
+				</bean>
+			</property>
+		</bean>
+
+		<!-- The filter is waiting for connections on URL suffixed with filterSuffix and presents SP metadata there -->
+		<bean id="metadataDisplayFilter" class="org.springframework.security.saml.metadata.MetadataDisplayFilter"/>
+
+		<!-- IDP Metadata configuration - paths to metadata of IDPs in circle of trust is here -->
+		<bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
+			<constructor-arg>
+				<list>
+					<!-- Example of classpath metadata with Extended Metadata -->
+					<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
+						<constructor-arg>
+							<bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
+								<constructor-arg>
+									<value type="java.io.File">classpath:sso_metadata.xml</value>
+								</constructor-arg>
+								<property name="parserPool" ref="parserPool"/>
+							</bean>
+						</constructor-arg>
+						<constructor-arg>
+							<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
+							</bean>
+						</constructor-arg>
+						<property name="metadataTrustCheck" value="false"/>
+					</bean>
+				</list>
+			</constructor-arg>
+		</bean>
+
+		<bean id="ldapUserAuthoritiesPopulator" class="org.apache.kylin.rest.security.AuthoritiesPopulator">
+			<constructor-arg index="0" ref="ldapSource" />
+			<constructor-arg index="1" value="${ldap.user.groupSearchBase}" />
+			<constructor-arg index="2" value="${acl.adminRole}" />
+			<constructor-arg index="3" value="${acl.defaultRole}" />
+		</bean>
+
+		<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
+			<constructor-arg index="0" value="${ldap.user.searchBase}" />
+			<constructor-arg index="1" value="${ldap.user.searchPattern}" />
+			<constructor-arg index="2" ref="ldapSource" />
+		</bean>
+
+		
+		<bean id="samlUserDetailsService" class="org.apache.kylin.rest.security.SAMLUserDetailsService">
+			<constructor-arg>
+				<bean id="ldapUserDetailsService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService">
+					<constructor-arg ref="userSearch" />
+					<constructor-arg ref="ldapUserAuthoritiesPopulator" />
+				</bean>
+			</constructor-arg>
+		</bean>
+		
+		<bean id="kylinAuthenticationProvider" class="org.apache.kylin.rest.security.KylinAuthenticationProvider">
+			<constructor-arg>
+				<!-- SAML Authentication Provider responsible for validating of received SAML messages -->
+				<bean id="samlAuthenticationProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider">
+					<!-- OPTIONAL property: can be used to store/load user data after login -->
+					<property name="userDetails" ref="samlUserDetailsService" />
+				</bean>
+			</constructor-arg>
+		</bean>
+		
+
+		<!-- Provider of default SAML Context -->
+		<!-- 
+		<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl"/>
+		-->
+		
+		<!-- Provider of a SAML Context behind a LoadBanlancer or reverse proxy -->
+		<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderLB">
+			<property name="scheme" value="${saml.context.scheme}"/>
+			<property name="serverName" value="${saml.context.serverName}"/>
+			<property name="serverPort" value="${saml.context.serverPort}"/>
+			<property name="includeServerPortInRequestURL" value="false"/>
+			<property name="contextPath" value="${saml.context.contextPath}"/>
+		</bean>
+		
+
+		<!-- Processing filter for WebSSO profile messages -->
+		<bean id="samlWebSSOProcessingFilter" class="org.springframework.security.saml.SAMLProcessingFilter">
+			<property name="authenticationManager" ref="samlAuthenticationManager"/>
+			<property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
+			<property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
+		</bean>
+
+		<!-- Processing filter for WebSSO Holder-of-Key profile -->
+		<bean id="samlWebSSOHoKProcessingFilter" class="org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter">
+			<property name="authenticationManager" ref="samlAuthenticationManager"/>
+			<property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
+			<property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
+		</bean>
+
+		<!-- Logout handler terminating local session -->
+		<bean id="logoutHandler"
+			  class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
+			<property name="invalidateHttpSession" value="false"/>
+		</bean>
+
+		<!-- Override default logout processing filter with the one processing SAML messages -->
+		<bean id="samlLogoutFilter" class="org.springframework.security.saml.SAMLLogoutFilter">
+			<constructor-arg index="0" ref="successLogoutHandler"/>
+			<constructor-arg index="1" ref="logoutHandler"/>
+			<constructor-arg index="2" ref="logoutHandler"/>
+		</bean>
+
+		<!-- Filter processing incoming logout messages -->
+		<!-- First argument determines URL user will be redirected to after successful global logout -->
+		<bean id="samlLogoutProcessingFilter" class="org.springframework.security.saml.SAMLLogoutProcessingFilter">
+			<constructor-arg index="0" ref="successLogoutHandler"/>
+			<constructor-arg index="1" ref="logoutHandler"/>
+		</bean>
+
+		<!-- Class loading incoming SAML messages from httpRequest stream -->
+		<bean id="processor" class="org.springframework.security.saml.processor.SAMLProcessorImpl">
+			<constructor-arg>
+				<list>
+					<ref bean="redirectBinding"/>
+					<ref bean="postBinding"/>
+					<ref bean="artifactBinding"/>
+					<ref bean="soapBinding"/>
+					<ref bean="paosBinding"/>
+				</list>
+			</constructor-arg>
+		</bean>
+
+		<!-- SAML 2.0 WebSSO Assertion Consumer -->
+		<bean id="webSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerImpl"/>
+
+		<!-- SAML 2.0 Holder-of-Key WebSSO Assertion Consumer -->
+		<bean id="hokWebSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>
+
+		<!-- SAML 2.0 Web SSO profile -->
+		<bean id="webSSOprofile" class="org.springframework.security.saml.websso.WebSSOProfileImpl"/>
+
+		<!-- SAML 2.0 Holder-of-Key Web SSO profile -->
+		<bean id="hokWebSSOProfile" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>
+
+		<!-- SAML 2.0 ECP profile -->
+		<bean id="ecpprofile" class="org.springframework.security.saml.websso.WebSSOProfileECPImpl"/>
+
+		<!-- SAML 2.0 Logout Profile -->
+		<bean id="logoutprofile" class="org.springframework.security.saml.websso.SingleLogoutProfileImpl"/>
+
+		<!-- Bindings, encoders and decoders used for creating and parsing messages -->
+		<bean id="postBinding" class="org.springframework.security.saml.processor.HTTPPostBinding">
+			<constructor-arg ref="parserPool"/>
+			<constructor-arg ref="velocityEngine"/>
+		</bean>
+
+		<bean id="redirectBinding" class="org.springframework.security.saml.processor.HTTPRedirectDeflateBinding">
+			<constructor-arg ref="parserPool"/>
+		</bean>
+
+		<bean id="artifactBinding" class="org.springframework.security.saml.processor.HTTPArtifactBinding">
+			<constructor-arg ref="parserPool"/>
+			<constructor-arg ref="velocityEngine"/>
+			<constructor-arg>
+				<bean class="org.springframework.security.saml.websso.ArtifactResolutionProfileImpl">
+					<constructor-arg>
+						<bean class="org.apache.commons.httpclient.HttpClient">
+							<constructor-arg>
+								<bean class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager"/>
+							</constructor-arg>
+						</bean>
+					</constructor-arg>
+					<property name="processor">
+						<bean class="org.springframework.security.saml.processor.SAMLProcessorImpl">
+							<constructor-arg ref="soapBinding"/>
+						</bean>
+					</property>
+				</bean>
+			</constructor-arg>
+		</bean>
+
+		<bean id="soapBinding" class="org.springframework.security.saml.processor.HTTPSOAP11Binding">
+			<constructor-arg ref="parserPool"/>
+		</bean>
+
+		<bean id="paosBinding" class="org.springframework.security.saml.processor.HTTPPAOS11Binding">
+			<constructor-arg ref="parserPool"/>
+		</bean>
+
+		<!-- Initialization of OpenSAML library-->
+		<bean class="org.springframework.security.saml.SAMLBootstrap"/>
+
+		<!-- Initialization of the velocity engine -->
+		<bean id="velocityEngine" class="org.springframework.security.saml.util.VelocityFactory" factory-method="getEngine"/>
+
+		<!-- XML parser pool needed for OpenSAML parsing -->
+		<bean id="parserPool" class="org.opensaml.xml.parse.StaticBasicParserPool" init-method="initialize">
+			<property name="builderFeatures">
+				<map>
+					<entry key="http://apache.org/xml/features/dom/defer-node-expansion" value="false"/>
+				</map>
+			</property>
+		</bean>
+
+		<bean id="parserPoolHolder" class="org.springframework.security.saml.parser.ParserPoolHolder"/>
+	</beans>
 </beans>
\ No newline at end of file