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>

Reply via email to