Repository: kylin
Updated Branches:
  refs/heads/2.0-rc e01e4b602 -> e8de0dc50


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/e8de0dc5
Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/e8de0dc5
Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/e8de0dc5

Branch: refs/heads/2.0-rc
Commit: e8de0dc5098b81d466691078c3c3192f463eb538
Parents: e01e4b6
Author: shaofengshi <[email protected]>
Authored: Fri Dec 11 17:32:18 2015 +0800
Committer: shaofengshi <[email protected]>
Committed: Fri Dec 11 17:34:50 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/e8de0dc5/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/e8de0dc5/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/e8de0dc5/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/e8de0dc5/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/e8de0dc5/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 31ab924..b91b8d9 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/e8de0dc5/server/pom.xml
----------------------------------------------------------------------
diff --git a/server/pom.xml b/server/pom.xml
index f2f9e32..515305d 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>2.8.1</version>

http://git-wip-us.apache.org/repos/asf/kylin/blob/e8de0dc5/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/e8de0dc5/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/e8de0dc5/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/e8de0dc5/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/e8de0dc5/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/e8de0dc5/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

Reply via email to