Repository: zeppelin Updated Branches: refs/heads/master c59f77dce -> a9ea68cf1
[ZEPPELIN-2598] Securing Zeppelin with OpenID Connect ### What is this PR for? Integrating Open ID connect login into Zeppelin leveraging Shiro(already present) and Pac4J( that needs to be in the classpath). Modifications done here should not affect any existing mechanisms but simply integrates and enable new once. ### What type of PR is it? [Improvement] ### What is the Jira issue? [ZEPPELIN-2598] ### Questions: * Does the licenses files need update? * Is there breaking changes for older versions? * Does this needs documentation? Author: andrea <andrea.peruffo1...@gmail.com> Closes #2373 from andreaTP/keycloak and squashes the following commits: 2d5af6d [andrea] merge with master 31270f2 [andrea] Merge remote-tracking branch 'apache/master' into keycloak 80c375d [andrea] fixed style issues on master 7ec8cdd [andrea] reverted to a minimum 545686d [andrea] fix username after direct login 03bbe30 [andrea] updates 4ce9121 [andrea] Enabling authentication with OpenId connect Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/a9ea68cf Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/a9ea68cf Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/a9ea68cf Branch: refs/heads/master Commit: a9ea68cf10bb8b65c8e118fd9c119302f56654df Parents: c59f77d Author: andrea <andrea.peruffo1...@gmail.com> Authored: Mon Jun 26 09:38:46 2017 +0100 Committer: Felix Cheung <felixche...@apache.org> Committed: Wed Jun 28 20:01:41 2017 -0700 ---------------------------------------------------------------------- docs/setup/security/shiro_authentication.md | 15 +++++++-------- pom.xml | 2 +- zeppelin-distribution/src/bin_license/LICENSE | 4 ++-- zeppelin-server/pom.xml | 1 - zeppelin-web/src/app/app.js | 15 ++++++++++++++- .../src/components/navbar/navbar.controller.js | 2 ++ zeppelin-web/src/components/navbar/navbar.html | 2 +- 7 files changed, 27 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a9ea68cf/docs/setup/security/shiro_authentication.md ---------------------------------------------------------------------- diff --git a/docs/setup/security/shiro_authentication.md b/docs/setup/security/shiro_authentication.md index d267007..347f694 100644 --- a/docs/setup/security/shiro_authentication.md +++ b/docs/setup/security/shiro_authentication.md @@ -128,7 +128,7 @@ Change the following values in the Shiro.ini file, and uncomment the line: ### LDAP -Two options exist for configuring an LDAP Realm. The simpler to use is the LdapGroupRealm. How ever it has limited +Two options exist for configuring an LDAP Realm. The simpler to use is the LdapGroupRealm. How ever it has limited flexibility with mapping of ldap groups to users and for authorization for user groups. A sample configuration file for this realm is given below. @@ -144,7 +144,7 @@ ldapRealm.contextFactory.authenticationMechanism = simple The other more flexible option is to use the LdapRealm. It allows for mapping of ldapgroups to roles and also allows for role/group based authentication into the zeppelin server. Sample configuration for this realm is given below. ``` -[main] +[main] ldapRealm=org.apache.zeppelin.realm.LdapRealm ldapRealm.contextFactory.authenticationMechanism=simple @@ -162,18 +162,18 @@ ldapRealm.groupObjectClass=groupofnames ldapRealm.userSearchAttributeName = sAMAccountName ldapRealm.memberAttribute=member # force usernames returned from ldap to lowercase useful for AD -ldapRealm.userLowerCase = true +ldapRealm.userLowerCase = true # ability set searchScopes subtree (default), one, base ldapRealm.userSearchScope = subtree; ldapRealm.groupSearchScope = subtree; ldapRealm.memberAttributeValueTemplate=cn={0},ou=people,dc=hadoop,dc=apache,dc=org -ldapRealm.contextFactory.systemUsername=uid=guest,ou=people,dc=hadoop,dc=apache,dc=org +ldapRealm.contextFactory.systemUsername=uid=guest,ou=people,dc=hadoop,dc=apache,dc=org ldapRealm.contextFactory.systemPassword=S{ALIAS=ldcSystemPassword} # enable support for nested groups using the LDAP_MATCHING_RULE_IN_CHAIN operator ldapRealm.groupSearchEnableMatchingRuleInChain = true # optional mapping from physical groups to logical application roles ldapRealm.rolesByGroup = LDN_USERS: user_role, NYK_USERS: user_role, HKG_USERS: user_role, GLOBAL_ADMIN: admin_role -# optional list of roles that are allowed to authenticate. Incase not present all groups are allowed to authenticate (login). +# optional list of roles that are allowed to authenticate. Incase not present all groups are allowed to authenticate (login). # This changes nothing for url specific permissions that will continue to work as specified in [urls]. ldapRealm.allowedRolesForAuthentication = admin_role,user_role ldapRealm.permissionsByRole= user_role = *:ToDoItemsJdo:*:*, *:ToDoItem:*:*; admin_role = * @@ -182,12 +182,12 @@ securityManager.realms = $ldapRealm ``` ### PAM -[PAM](https://en.wikipedia.org/wiki/Pluggable_authentication_module) authentication support allows the reuse of existing authentication +[PAM](https://en.wikipedia.org/wiki/Pluggable_authentication_module) authentication support allows the reuse of existing authentication moduls on the host where Zeppelin is running. On a typical system modules are configured per service for example sshd, passwd, etc. under `/etc/pam.d/`. You can either reuse one of these services or create your own for Zeppelin. Activiting PAM authentication requires two parameters: 1. realm: The Shiro realm being used 2. service: The service configured under `/etc/pam.d/` to be used. The name here needs to be the same as the file name under `/etc/pam.d/` - + ``` [main] pamRealm=org.apache.zeppelin.realm.PamRealm @@ -232,4 +232,3 @@ If you want to grant this permission to other users, you can change **roles[ ]** ## Other authentication methods - [HTTP Basic Authentication using NGINX](./authentication_nginx.html) - http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a9ea68cf/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index d9b6375..182b508 100644 --- a/pom.xml +++ b/pom.xml @@ -107,7 +107,7 @@ <commons.collections.version>3.2.1</commons.collections.version> <commons.logging.version>1.1.1</commons.logging.version> <commons.cli.version>1.3.1</commons.cli.version> - <shiro.version>1.2.3</shiro.version> + <shiro.version>1.3.2</shiro.version> <!-- test library versions --> <junit.version>4.12</junit.version> http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a9ea68cf/zeppelin-distribution/src/bin_license/LICENSE ---------------------------------------------------------------------- diff --git a/zeppelin-distribution/src/bin_license/LICENSE b/zeppelin-distribution/src/bin_license/LICENSE index 37fc936..51bc91c 100644 --- a/zeppelin-distribution/src/bin_license/LICENSE +++ b/zeppelin-distribution/src/bin_license/LICENSE @@ -95,8 +95,8 @@ The following components are provided under Apache License. (Apache 2.0) Lucene Suggest (org.apache.lucene:lucene-suggest:5.3.1 - http://lucene.apache.org/lucene-parent/lucene-suggest) (Apache 2.0) Elasticsearch: Core (org.elasticsearch:elasticsearch:2.1.0 - http://nexus.sonatype.org/oss-repository-hosting.html/parent/elasticsearch) (Apache 2.0) Joda convert (org.joda:joda-convert:1.8.1 - http://joda-convert.sourceforge.net) - (Apache 2.0) Shiro Core (org.apache.shiro:shiro-core:1.2.3 - https://shiro.apache.org) - (Apache 2.0) Shiro Web (org.apache.shiro:shiro-web:1.2.3 - https://shiro.apache.org) + (Apache 2.0) Shiro Core (org.apache.shiro:shiro-core:1.3.2 - https://shiro.apache.org) + (Apache 2.0) Shiro Web (org.apache.shiro:shiro-web:1.3.2 - https://shiro.apache.org) (Apache 2.0) SnakeYAML (org.yaml:snakeyaml:1.15 - http://www.snakeyaml.org) (Apache 2.0) Protocol Buffers (com.google.protobuf:protobuf-java:2.5.0 - https://github.com/google/protobuf/releases) (Apache 2.0) Alluxio Shell (org.alluxio:alluxio-shell:1.0.0 - http://alluxio.org) http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a9ea68cf/zeppelin-server/pom.xml ---------------------------------------------------------------------- diff --git a/zeppelin-server/pom.xml b/zeppelin-server/pom.xml index bf4f52a..295f6eb 100644 --- a/zeppelin-server/pom.xml +++ b/zeppelin-server/pom.xml @@ -478,7 +478,6 @@ </dependencies> </dependencyManagement> </profile> - <profile> <id>using-source-tree</id> <activation> http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a9ea68cf/zeppelin-web/src/app/app.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/app.js b/zeppelin-web/src/app/app.js index dad04f0..575b34a 100644 --- a/zeppelin-web/src/app/app.js +++ b/zeppelin-web/src/app/app.js @@ -146,6 +146,7 @@ let zeppelinWebApp = angular.module('zeppelinWebApp', requiredModules) // handel logout on API failure .config(function ($httpProvider, $provide) { + $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest' $provide.factory('httpInterceptor', function ($q, $rootScope) { return { 'responseError': function (rejection) { @@ -175,12 +176,24 @@ function auth () { }, crossDomain: true }) - return $http.get(baseUrlSrv.getRestApiBase() + '/security/ticket').then(function (response) { + let config = {headers: { 'X-Requested-With': 'XMLHttpRequest' }} + return $http.get(baseUrlSrv.getRestApiBase() + '/security/ticket', config).then(function (response) { zeppelinWebApp.run(function ($rootScope) { $rootScope.ticket = angular.fromJson(response.data).body + + $rootScope.ticket.screenUsername = $rootScope.ticket.principal + if ($rootScope.ticket.principal.startsWith('#Pac4j')) { + let re = ', name=(.*?),' + $rootScope.ticket.screenUsername = $rootScope.ticket.principal.match(re)[1] + } }) }, function (errorResponse) { // Handle error case + let redirect = errorResponse.headers('Location') + if (errorResponse.status === 401 && redirect !== undefined) { + // Handle page redirect + window.location.href = redirect + } }) } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a9ea68cf/zeppelin-web/src/components/navbar/navbar.controller.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/components/navbar/navbar.controller.js b/zeppelin-web/src/components/navbar/navbar.controller.js index 0b6a279..28a900e 100644 --- a/zeppelin-web/src/components/navbar/navbar.controller.js +++ b/zeppelin-web/src/components/navbar/navbar.controller.js @@ -95,6 +95,7 @@ function NavCtrl ($scope, $rootScope, $http, $routeParams, $location, $http.post(logoutURL).error(function () { $rootScope.userName = '' $rootScope.ticket.principal = '' + $rootScope.ticket.screenUsername = '' $rootScope.ticket.ticket = '' $rootScope.ticket.roles = '' BootstrapDialog.show({ @@ -131,6 +132,7 @@ function NavCtrl ($scope, $rootScope, $http, $routeParams, $location, }) $scope.$on('loginSuccess', function (event, param) { + $rootScope.ticket.screenUsername = $rootScope.ticket.principal listConfigurations() loadNotes() getHomeNote() http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a9ea68cf/zeppelin-web/src/components/navbar/navbar.html ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/components/navbar/navbar.html b/zeppelin-web/src/components/navbar/navbar.html index acbe1d6..d5e6668 100644 --- a/zeppelin-web/src/components/navbar/navbar.html +++ b/zeppelin-web/src/components/navbar/navbar.html @@ -90,7 +90,7 @@ limitations under the License. <i ng-if="!navbar.connected" class="fa fa-circle server-disconnected" uib-tooltip="WebSocket Disconnected" tooltip-placement="bottom" style="margin-top: 7px; vertical-align: top"></i> <button ng-if="ticket" class="nav-btn dropdown-toggle" type="button" data-toggle="dropdown" style="margin:11px 5px 0 0; padding-left: 0px;"> - <span class="username">{{ticket.principal}}</span> + <span class="username">{{ticket.screenUsername}}</span> <span class="caret" style="margin-bottom: 8px"></span> </button> <span ng-if="!ticket" style="margin: 5px;"></span>