ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mpapirkovs...@apache.org
Subject [2/2] ambari git commit: AMBARI-13342. Allow access to callers with valid Knox authorization cookie. (mpapirkovskyy)
Date Wed, 11 Nov 2015 15:32:32 GMT
AMBARI-13342. Allow access to callers with valid Knox authorization cookie. (mpapirkovskyy)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/40ec645a
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/40ec645a
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/40ec645a

Branch: refs/heads/trunk
Commit: 40ec645a59b9c27e180d5686ca7513933bd98383
Parents: d8bf840
Author: Myroslav Papirkovskyy <mpapyrkovskyy@hortonworks.com>
Authored: Mon Nov 9 20:09:12 2015 +0200
Committer: Myroslav Papirkovskyi <mpapyrkovskyy@hortonworks.com>
Committed: Wed Nov 11 17:32:03 2015 +0200

----------------------------------------------------------------------
 ambari-server/pom.xml                           |  12 +
 .../ambari/server/api/AmbariErrorHandler.java   |  17 +-
 .../server/configuration/Configuration.java     |  56 ++++
 .../AmbariManagementControllerImpl.java         |   6 +-
 .../ambari/server/controller/AmbariServer.java  |   3 +
 .../server/controller/ControllerModule.java     |   4 +
 .../ambari/server/controller/UserResponse.java  |  24 +-
 .../internal/UserPrivilegeResourceProvider.java |   4 +
 .../internal/UserResourceProvider.java          |   4 +
 .../apache/ambari/server/orm/dao/UserDAO.java   |  14 +
 .../ambari/server/orm/entities/UserEntity.java  |  31 +-
 .../AmbariAuthorizationFilter.java              |   8 +-
 .../server/security/authorization/User.java     |  11 +-
 .../server/security/authorization/UserType.java |  24 ++
 .../server/security/authorization/Users.java    |  82 ++++-
 .../authorization/jwt/JwtAuthentication.java    |  78 +++++
 .../jwt/JwtAuthenticationFilter.java            | 329 +++++++++++++++++++
 .../jwt/JwtAuthenticationProperties.java        |  85 +++++
 .../security/encryption/CertificateUtils.java   |  68 ++++
 .../server/upgrade/UpgradeCatalog220.java       |  12 +
 ambari-server/src/main/python/ambari-server.py  |   8 +-
 .../main/python/ambari_server/setupActions.py   |   3 +-
 .../src/main/python/ambari_server/setupSso.py   | 121 +++++++
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |   3 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |   3 +-
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |   5 +-
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |   5 +-
 .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql |   3 +-
 .../resources/Ambari-DDL-SQLServer-CREATE.sql   |   9 +-
 .../src/main/resources/properties.json          |   1 +
 .../webapp/WEB-INF/spring-security.xml          |   5 +-
 .../server/api/AmbariErrorHandlerTest.java      |   4 +-
 .../jwt/JwtAuthenticationFilterTest.java        | 244 ++++++++++++++
 33 files changed, 1242 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index 17e9ea9..5885693 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -2008,6 +2008,18 @@
       <artifactId>ehcache</artifactId>
       <version>2.10.0</version>
     </dependency>
+    <dependency>
+      <groupId>com.nimbusds</groupId>
+      <artifactId>nimbus-jose-jwt</artifactId>
+      <version>3.9</version>
+      <scope>compile</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>org.bouncycastle</groupId>
+          <artifactId>bcprov-jdk15on</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
   </dependencies>
 
   <pluginRepositories>

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java
index ee4e56f..6ec3ceb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java
@@ -21,6 +21,8 @@ package org.apache.ambari.server.api;
 import com.google.gson.Gson;
 import com.google.inject.Inject;
 import com.google.inject.name.Named;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationProperties;
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.http.MimeTypes;
 import org.eclipse.jetty.server.AbstractHttpConnection;
@@ -33,12 +35,17 @@ import java.io.IOException;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
+/**
+ * Custom error handler for Jetty to return response as JSON instead of stub http page
+ */
 public class AmbariErrorHandler extends ErrorHandler {
   private final Gson gson;
+  private Configuration configuration;
 
   @Inject
-  public AmbariErrorHandler(@Named("prettyGson") Gson prettyGson) {
+  public AmbariErrorHandler(@Named("prettyGson") Gson prettyGson, Configuration configuration) {
     this.gson = prettyGson;
+    this.configuration = configuration;
   }
 
   @Override
@@ -57,6 +64,14 @@ public class AmbariErrorHandler extends ErrorHandler {
     }
     errorMap.put("message", message);
 
+    if (code == HttpServletResponse.SC_FORBIDDEN) {
+      //if SSO is configured we should provide info about it in case of access error
+      JwtAuthenticationProperties jwtProperties = configuration.getJwtProperties();
+      if (jwtProperties != null) {
+        errorMap.put("jwtProviderUrl", jwtProperties.getAuthenticationProviderUrl());
+      }
+    }
+
     gson.toJson(errorMap, response.getWriter());
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index 12f6bca..ee26264 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -32,8 +32,10 @@ import org.apache.ambari.server.orm.PersistenceType;
 import org.apache.ambari.server.orm.entities.StageEntity;
 import org.apache.ambari.server.security.ClientSecurityType;
 import org.apache.ambari.server.security.authorization.LdapServerProperties;
+import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationProperties;
 import org.apache.ambari.server.security.encryption.CredentialProvider;
 import org.apache.ambari.server.state.stack.OsFamily;
+import org.apache.ambari.server.security.encryption.CertificateUtils;
 import org.apache.ambari.server.utils.Parallel;
 import org.apache.ambari.server.utils.ShellCommandUtil;
 import org.apache.commons.io.FileUtils;
@@ -55,6 +57,9 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
 
+import java.security.cert.CertificateException;
+import java.security.interfaces.RSAPublicKey;
+
 
 /**
  * Ambari configuration.
@@ -191,6 +196,14 @@ public class Configuration {
   public static final String ROLLING_UPGRADE_MIN_STACK_DEFAULT = "HDP-2.2";
   public static final String ROLLING_UPGRADE_MAX_STACK_DEFAULT = "";
   public static final String ROLLING_UPGRADE_SKIP_PACKAGES_PREFIXES_DEFAULT = "";
+  public static final String JWT_AUTH_ENBABLED = "authentication.jwt.enabled";
+  public static final String JWT_AUTH_PROVIDER_URL = "authentication.jwt.providerUrl";
+  public static final String JWT_PUBLIC_KEY = "authentication.jwt.publicKey";
+  public static final String JWT_AUDIENCES = "authentication.jwt.audiences";
+  public static final String JWT_COOKIE_NAME = "authentication.jwt.cookieName";
+  public static final String JWT_ORIGINAL_URL_QUERY_PARAM = "authentication.jwt.originalUrlParamName";
+  public static final String JWT_COOKIE_NAME_DEFAULT = "hadoop-jwt";
+  public static final String JWT_ORIGINAL_URL_QUERY_PARAM_DEFAULT = "originalUrl";
 
   public static final String SERVER_JDBC_CONNECTION_POOL = "server.jdbc.connection-pool";
   public static final String SERVER_JDBC_CONNECTION_POOL_MIN_SIZE = "server.jdbc.connection-pool.min-size";
@@ -2312,6 +2325,49 @@ public class Configuration {
   }
 
   /**
+   * Get set of properties desribing SSO configuration (JWT)
+   */
+  public JwtAuthenticationProperties getJwtProperties() {
+    boolean enableJwt = Boolean.valueOf(properties.getProperty(JWT_AUTH_ENBABLED, "false"));
+
+    if (enableJwt) {
+      String providerUrl = properties.getProperty(JWT_AUTH_PROVIDER_URL);
+      if (providerUrl == null) {
+        LOG.error("JWT authentication provider URL not specified. JWT auth will be disabled.", providerUrl);
+        return null;
+      }
+      String publicKeyPath = properties.getProperty(JWT_PUBLIC_KEY);
+      if (publicKeyPath == null) {
+        LOG.error("Public key pem not specified for JWT auth provider {}. JWT auth will be disabled.", providerUrl);
+        return null;
+      }
+      try {
+        RSAPublicKey publicKey = CertificateUtils.getPublicKeyFromFile(publicKeyPath);
+        JwtAuthenticationProperties jwtProperties = new JwtAuthenticationProperties();
+        jwtProperties.setAuthenticationProviderUrl(providerUrl);
+        jwtProperties.setPublicKey(publicKey);
+
+        jwtProperties.setCookieName(properties.getProperty(JWT_COOKIE_NAME, JWT_COOKIE_NAME_DEFAULT));
+        jwtProperties.setAudiencesString(properties.getProperty(JWT_AUDIENCES));
+        jwtProperties.setOriginalUrlQueryParam(
+          properties.getProperty(JWT_ORIGINAL_URL_QUERY_PARAM, JWT_ORIGINAL_URL_QUERY_PARAM_DEFAULT));
+
+        return jwtProperties;
+
+      } catch (IOException e) {
+        LOG.error("Unable to read public certificate file. JWT auth will be disabled.", e);
+        return null;
+      } catch (CertificateException e) {
+        LOG.error("Unable to parse public certificate file. JWT auth will be disabled.", e);
+        return null;
+      }
+    } else {
+      return null;
+    }
+
+  }
+
+  /**
    * Gets whether to use experiemental concurrent processing to convert
    * {@link StageEntity} instances into {@link Stage} instances. The default is
    * {@code false}.

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 49a8d8b..8dd7a04 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -3202,7 +3202,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
       // get them all
       if (null == r.getUsername()) {
         for (User u : users.getAllUsers()) {
-          UserResponse resp = new UserResponse(u.getUserName(), u.isLdapUser(), u.isActive(), u.isAdmin());
+          UserResponse resp = new UserResponse(u.getUserName(), u.getUserType(), u.isLdapUser(), u.isActive(), u
+              .isAdmin());
           resp.setGroups(new HashSet<String>(u.getGroups()));
           responses.add(resp);
         }
@@ -3217,7 +3218,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
                 + r.getUsername() + "'");
           }
         } else {
-          UserResponse resp = new UserResponse(u.getUserName(), u.isLdapUser(), u.isActive(), u.isAdmin());
+          UserResponse resp = new UserResponse(u.getUserName(), u.getUserType(), u.isLdapUser(), u.isActive(), u
+              .isAdmin());
           resp.setGroups(new HashSet<String>(u.getGroups()));
           responses.add(resp);
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 71e8082..a3c5fcc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -89,6 +89,7 @@ import org.apache.ambari.server.security.authorization.AmbariLdapAuthenticationP
 import org.apache.ambari.server.security.authorization.AmbariLocalUserDetailsService;
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.ambari.server.security.authorization.internal.AmbariInternalAuthenticationProvider;
+import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationFilter;
 import org.apache.ambari.server.security.ldap.AmbariLdapDataPopulator;
 import org.apache.ambari.server.security.unsecured.rest.CertificateDownload;
 import org.apache.ambari.server.security.unsecured.rest.CertificateSign;
@@ -275,6 +276,8 @@ public class AmbariServer {
           injector.getInstance(AmbariAuthorizationFilter.class));
       factory.registerSingleton("ambariInternalAuthenticationProvider",
           injector.getInstance(AmbariInternalAuthenticationProvider.class));
+      factory.registerSingleton("ambariJwtAuthenticationFilter",
+          injector.getInstance(JwtAuthenticationFilter.class));
 
       //Spring Security xml config depends on this Bean
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index 20fe2c7..823ac8a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -65,6 +65,7 @@ import org.apache.ambari.server.orm.DBAccessorImpl;
 import org.apache.ambari.server.orm.PersistenceType;
 import org.apache.ambari.server.scheduler.ExecutionScheduler;
 import org.apache.ambari.server.scheduler.ExecutionSchedulerImpl;
+import org.apache.ambari.server.security.AmbariEntryPoint;
 import org.apache.ambari.server.security.SecurityHelper;
 import org.apache.ambari.server.security.SecurityHelperImpl;
 import org.apache.ambari.server.security.encryption.CredentialStoreService;
@@ -119,6 +120,7 @@ import org.springframework.core.type.filter.AnnotationTypeFilter;
 import org.springframework.core.type.filter.AssignableTypeFilter;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.crypto.password.StandardPasswordEncoder;
+import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.util.ClassUtils;
 import org.springframework.web.filter.DelegatingFilterProxy;
 
@@ -346,6 +348,8 @@ public class ControllerModule extends AbstractModule {
 
     bind(PersistedState.class).to(PersistedStateImpl.class);
 
+    bind(AuthenticationEntryPoint.class).to(AmbariEntryPoint.class).in(Scopes.SINGLETON);
+
     requestStaticInjection(ExecutionCommandWrapper.class);
     requestStaticInjection(DatabaseChecker.class);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserResponse.java
index 868635c..d481327 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserResponse.java
@@ -17,6 +17,8 @@
  */
 package org.apache.ambari.server.controller;
 
+import org.apache.ambari.server.security.authorization.UserType;
+
 import java.util.Collections;
 import java.util.Set;
 
@@ -26,16 +28,26 @@ import java.util.Set;
 public class UserResponse {
 
   private final String userName;
+  private final UserType userType;
   private final boolean isLdapUser;
   private final boolean isActive;
   private final boolean isAdmin;
   private Set<String> groups = Collections.emptySet();
 
+  public UserResponse(String userName, UserType userType, boolean isLdapUser, boolean isActive, boolean isAdmin) {
+    this.userName = userName;
+    this.userType = userType;
+    this.isLdapUser = isLdapUser;
+    this.isActive = isActive;
+    this.isAdmin = isAdmin;
+  }
+
   public UserResponse(String name, boolean isLdapUser, boolean isActive, boolean isAdmin) {
     this.userName = name;
     this.isLdapUser = isLdapUser;
     this.isActive = isActive;
     this.isAdmin = isAdmin;
+    this.userType = UserType.LOCAL;
   }
 
   public String getUsername() {
@@ -57,17 +69,15 @@ public class UserResponse {
 
     UserResponse that = (UserResponse) o;
 
-    if (userName != null ?
-        !userName.equals(that.userName) : that.userName != null) {
-      return false;
-    }
+    if (userName != null ? !userName.equals(that.userName) : that.userName != null) return false;
+    return userType == that.userType;
 
-    return true;
   }
 
   @Override
   public int hashCode() {
     int result = userName != null ? userName.hashCode() : 0;
+    result = 31 * result + (userType != null ? userType.hashCode() : 0);
     return result;
   }
 
@@ -85,4 +95,8 @@ public class UserResponse {
   public boolean isAdmin() {
     return isAdmin;
   }
+
+  public UserType getUserType() {
+    return userType;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java
index cdc8c8a..0621286 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java
@@ -42,6 +42,7 @@ import org.apache.ambari.server.orm.entities.ResourceTypeEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.orm.entities.ViewEntity;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
+import org.apache.ambari.server.security.authorization.UserType;
 
 /**
  * Resource provider for user privilege resources.
@@ -159,6 +160,9 @@ public class UserPrivilegeResourceProvider extends ReadOnlyResourceProvider {
           userEntity = userDAO.findLdapUserByName(userName);
         }
         if (userEntity == null) {
+          userEntity = userDAO.findUserByNameAndType(userName, UserType.JWT);
+        }
+        if (userEntity == null) {
           throw new SystemException("User " + userName + " was not found");
         }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java
index 35f9db5..b993450 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java
@@ -41,6 +41,7 @@ class UserResourceProvider extends AbstractControllerResourceProvider {
   protected static final String USER_PASSWORD_PROPERTY_ID     = PropertyHelper.getPropertyId("Users", "password");
   protected static final String USER_OLD_PASSWORD_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "old_password");
   protected static final String USER_LDAP_USER_PROPERTY_ID    = PropertyHelper.getPropertyId("Users", "ldap_user");
+  protected static final String USER_TYPE_PROPERTY_ID         = PropertyHelper.getPropertyId("Users", "user_type");
   protected static final String USER_ACTIVE_PROPERTY_ID       = PropertyHelper.getPropertyId("Users", "active");
   protected static final String USER_GROUPS_PROPERTY_ID       = PropertyHelper.getPropertyId("Users", "groups");
   protected static final String USER_ADMIN_PROPERTY_ID        = PropertyHelper.getPropertyId("Users", "admin");
@@ -119,6 +120,9 @@ class UserResourceProvider extends AbstractControllerResourceProvider {
       setResourceProperty(resource, USER_LDAP_USER_PROPERTY_ID,
           userResponse.isLdapUser(), requestedIds);
 
+      setResourceProperty(resource, USER_TYPE_PROPERTY_ID,
+          userResponse.getUserType(), requestedIds);
+
       setResourceProperty(resource, USER_ACTIVE_PROPERTY_ID,
           userResponse.isActive(), requestedIds);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java
index 12f975e..1bd83f8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java
@@ -35,6 +35,7 @@ import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.security.authorization.UserType;
 
 @Singleton
 public class UserDAO {
@@ -67,6 +68,19 @@ public class UserDAO {
   }
 
   @RequiresSession
+  public UserEntity findUserByNameAndType(String userName, UserType userType) {
+    TypedQuery<UserEntity> query = entityManagerProvider.get().createQuery("SELECT user FROM UserEntity user WHERE " +
+        "user.userType=:type AND user.userName=:name", UserEntity.class);
+    query.setParameter("type", userType);
+    query.setParameter("name", userName);
+    try {
+      return query.getSingleResult();
+    } catch (NoResultException e) {
+      return null;
+    }
+  }
+
+  @RequiresSession
   public UserEntity findLocalUserByName(String userName) {
     TypedQuery<UserEntity> query = entityManagerProvider.get().createNamedQuery("localUserByName", UserEntity.class);
     query.setParameter("username", userName.toLowerCase());

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
index 32dbbf5..5b8360a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
@@ -17,18 +17,25 @@
  */
 package org.apache.ambari.server.orm.entities;
 
+import org.apache.ambari.server.security.authorization.UserType;
+
 import javax.persistence.*;
 
 import java.util.Date;
 import java.util.HashSet;
 import java.util.Set;
 
-@Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_name", "ldap_user"})})
+@Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_name", "user_type"})})
 @Entity
 @NamedQueries({
-    @NamedQuery(name = "userByName", query = "SELECT user_entity from UserEntity user_entity where lower(user_entity.userName)=:username"),
-    @NamedQuery(name = "localUserByName", query = "SELECT user_entity FROM UserEntity user_entity where lower(user_entity.userName)=:username AND user_entity.ldapUser=false"),
-    @NamedQuery(name = "ldapUserByName", query = "SELECT user_entity FROM UserEntity user_entity where lower(user_entity.userName)=:username AND user_entity.ldapUser=true")
+    @NamedQuery(name = "userByName", query = "SELECT user_entity from UserEntity user_entity " +
+        "where lower(user_entity.userName)=:username"),
+    @NamedQuery(name = "localUserByName", query = "SELECT user_entity FROM UserEntity user_entity " +
+        "where lower(user_entity.userName)=:username AND " +
+        "user_entity.userType=org.apache.ambari.server.security.authorization.UserType.LOCAL"),
+    @NamedQuery(name = "ldapUserByName", query = "SELECT user_entity FROM UserEntity user_entity " +
+        "where lower(user_entity.userName)=:username AND " +
+        "user_entity.userType=org.apache.ambari.server.security.authorization.UserType.LDAP")
 })
 @TableGenerator(name = "user_id_generator",
     table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value"
@@ -49,6 +56,11 @@ public class UserEntity {
   @Column(name = "ldap_user")
   private Integer ldapUser = 0;
 
+  @Column(name = "user_type")
+  @Enumerated(EnumType.STRING)
+  @Basic
+  private UserType userType = UserType.LOCAL;
+
   @Column(name = "user_password")
   @Basic
   private String userPassword;
@@ -99,9 +111,18 @@ public class UserEntity {
       this.ldapUser = null;
     } else {
       this.ldapUser = ldapUser ? 1 : 0;
+      this.userType = ldapUser ? UserType.LDAP : UserType.LOCAL;
     }
   }
 
+  public UserType getUserType() {
+    return userType;
+  }
+
+  public void setUserType(UserType userType) {
+    this.userType = userType;
+  }
+
   public String getUserPassword() {
     return userPassword;
   }
@@ -176,6 +197,7 @@ public class UserEntity {
     if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false;
     if (createTime != null ? !createTime.equals(that.createTime) : that.createTime != null) return false;
     if (ldapUser != null ? !ldapUser.equals(that.ldapUser) : that.ldapUser != null) return false;
+    if (userType != null ? !userType.equals(that.userType) : that.userType != null) return false;
     if (userName != null ? !userName.equals(that.userName) : that.userName != null) return false;
     if (userPassword != null ? !userPassword.equals(that.userPassword) : that.userPassword != null) return false;
     if (active != null ? !active.equals(that.active) : that.active != null) return false;
@@ -189,6 +211,7 @@ public class UserEntity {
     result = 31 * result + (userName != null ? userName.hashCode() : 0);
     result = 31 * result + (userPassword != null ? userPassword.hashCode() : 0);
     result = 31 * result + (ldapUser != null ? ldapUser.hashCode() : 0);
+    result = 31 * result + (userType != null ? userType.hashCode() : 0);
     result = 31 * result + (createTime != null ? createTime.hashCode() : 0);
     result = 31 * result + (active != null ? active.hashCode() : 0);
     return result;

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
index 0abbf45..46b751d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
@@ -95,13 +95,15 @@ public class AmbariAuthorizationFilter implements Filter {
         context.setAuthentication(new InternalAuthenticationToken(token));
       } else {
         // for view access, we should redirect to the Ambari login
-        if(requestURI.matches(VIEWS_CONTEXT_ALL_PATTERN)) {
-          String queryString  = httpRequest.getQueryString();
+        if (requestURI.matches(VIEWS_CONTEXT_ALL_PATTERN)) {
+          String queryString = httpRequest.getQueryString();
           String requestedURL = queryString == null ? requestURI : (requestURI + '?' + queryString);
-          String redirectURL  = httpResponse.encodeRedirectURL(LOGIN_REDIRECT_BASE + requestedURL);
+          String redirectURL = httpResponse.encodeRedirectURL(LOGIN_REDIRECT_BASE + requestedURL);
 
           httpResponse.sendRedirect(redirectURL);
           return;
+        } else {
+          httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Authentication required");
         }
       }
     } else {

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
index e72d958..ab48ddd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
@@ -20,11 +20,13 @@ package org.apache.ambari.server.security.authorization;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
+import java.util.List;
 
 import org.apache.ambari.server.orm.entities.MemberEntity;
 import org.apache.ambari.server.orm.entities.PermissionEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
+import org.springframework.security.core.GrantedAuthority;
 
 /**
  * Describes user of web-services
@@ -33,15 +35,18 @@ public class User {
   final int userId;
   final String userName;
   final boolean ldapUser;
+  final UserType userType;
   final Date createTime;
   final boolean active;
   final Collection<String> groups = new ArrayList<String>();
   boolean admin = false;
+  final List<GrantedAuthority> authorities = new ArrayList<>();
 
   public User(UserEntity userEntity) {
     userId = userEntity.getUserId();
     userName = userEntity.getUserName();
     createTime = userEntity.getCreateTime();
+    userType = userEntity.getUserType();
     ldapUser = userEntity.getLdapUser();
     active = userEntity.getActive();
     for (MemberEntity memberEntity : userEntity.getMemberEntities()) {
@@ -67,6 +72,10 @@ public class User {
     return ldapUser;
   }
 
+  public UserType getUserType() {
+    return userType;
+  }
+
   public Date getCreateTime() {
     return createTime;
   }
@@ -85,6 +94,6 @@ public class User {
 
   @Override
   public String toString() {
-    return (ldapUser ? "[LDAP]" : "[LOCAL]") + userName;
+    return "[" + getUserType() + "]" + userName;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserType.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserType.java
new file mode 100644
index 0000000..aa9f3e0
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserType.java
@@ -0,0 +1,24 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.security.authorization;
+
+public enum UserType {
+  LOCAL,
+  LDAP,
+  JWT
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
index 867cd11..29b9ec3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
@@ -17,13 +17,7 @@
  */
 package org.apache.ambari.server.security.authorization;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import javax.persistence.EntityManager;
 
 import org.apache.ambari.server.AmbariException;
@@ -50,6 +44,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.crypto.password.PasswordEncoder;
@@ -108,6 +103,11 @@ public class Users {
     return (null == userEntity) ? null : new User(userEntity);
   }
 
+  public User getUser(String userName, UserType userType) {
+    UserEntity userEntity = userDAO.findUserByNameAndType(userName, userType);
+    return (null == userEntity) ? null : new User(userEntity);
+  }
+
   /**
    * Modifies password of local user
    * @throws AmbariException
@@ -238,7 +238,6 @@ public class Users {
    * @param ldapUser is user LDAP
    * @throws AmbariException if user already exists
    */
-  @Transactional
   public synchronized void createUser(String userName, String password, Boolean active, Boolean admin, Boolean ldapUser) throws AmbariException {
 
     if (getAnyUser(userName) != null) {
@@ -275,7 +274,44 @@ public class Users {
     }
   }
 
-  @Transactional
+  public synchronized void createUser(String userName, String password, UserType userType, Boolean active, Boolean
+      admin) throws AmbariException {
+    if (getUser(userName, userType) != null) {
+      throw new AmbariException("User " + userName + " already exists");
+    }
+
+    PrincipalTypeEntity principalTypeEntity = principalTypeDAO.findById(PrincipalTypeEntity.USER_PRINCIPAL_TYPE);
+    if (principalTypeEntity == null) {
+      principalTypeEntity = new PrincipalTypeEntity();
+      principalTypeEntity.setId(PrincipalTypeEntity.USER_PRINCIPAL_TYPE);
+      principalTypeEntity.setName(PrincipalTypeEntity.USER_PRINCIPAL_TYPE_NAME);
+      principalTypeDAO.create(principalTypeEntity);
+    }
+    PrincipalEntity principalEntity = new PrincipalEntity();
+    principalEntity.setPrincipalType(principalTypeEntity);
+    principalDAO.create(principalEntity);
+
+    UserEntity userEntity = new UserEntity();
+    userEntity.setUserName(userName);
+    if (userType == null || userType == UserType.LOCAL) {
+      //passwords should be stored for local users only
+      userEntity.setUserPassword(passwordEncoder.encode(password));
+    }
+    userEntity.setPrincipal(principalEntity);
+    if (active != null) {
+      userEntity.setActive(active);
+    }
+    if (userType != null) {
+      userEntity.setUserType(userType);
+    }
+
+    userDAO.create(userEntity);
+
+    if (admin != null && admin) {
+      grantAdminPrivilege(userEntity.getUserId());
+    }
+  }
+
   public synchronized void removeUser(User user) throws AmbariException {
     UserEntity userEntity = userDAO.findByPK(user.getUserId());
     if (userEntity != null) {
@@ -654,4 +690,32 @@ public class Users {
     entityManagerProvider.get().getEntityManagerFactory().getCache().evictAll();
   }
 
+  public Collection<AmbariGrantedAuthority> getUserAuthorities(String userName, UserType userType) {
+    UserEntity userEntity = userDAO.findUserByNameAndType(userName, userType);
+    if (userEntity == null) {
+      return Collections.emptyList();
+    }
+
+    // get all of the privileges for the user
+    List<PrincipalEntity> principalEntities = new LinkedList<PrincipalEntity>();
+
+    principalEntities.add(userEntity.getPrincipal());
+
+    List<MemberEntity> memberEntities = memberDAO.findAllMembersByUser(userEntity);
+
+    for (MemberEntity memberEntity : memberEntities) {
+      principalEntities.add(memberEntity.getGroup().getPrincipal());
+    }
+
+    List<PrivilegeEntity> privilegeEntities = privilegeDAO.findAllByPrincipal(principalEntities);
+
+    Set<AmbariGrantedAuthority> authorities = new HashSet<>(privilegeEntities.size());
+
+    for (PrivilegeEntity privilegeEntity : privilegeEntities) {
+      authorities.add(new AmbariGrantedAuthority(privilegeEntity));
+    }
+
+    return authorities;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthentication.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthentication.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthentication.java
new file mode 100644
index 0000000..53826c0
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthentication.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.security.authorization.jwt;
+
+import com.nimbusds.jwt.SignedJWT;
+import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
+import org.apache.ambari.server.security.authorization.User;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+
+import java.util.Collection;
+
+/**
+ * Internal token which describes JWT authentication
+ */
+public class JwtAuthentication implements Authentication {
+
+  private SignedJWT token;
+  private User user;
+  private Collection<AmbariGrantedAuthority> userAuthorities;
+  private boolean authenticated = false;
+
+  public JwtAuthentication(SignedJWT token, User user, Collection<AmbariGrantedAuthority> userAuthorities) {
+    this.token = token;
+    this.user = user;
+    this.userAuthorities = userAuthorities;
+  }
+
+  @Override
+  public Collection<? extends AmbariGrantedAuthority> getAuthorities() {
+    return userAuthorities;
+  }
+
+  @Override
+  public SignedJWT getCredentials() {
+    return token;
+  }
+
+  @Override
+  public Object getDetails() {
+    return null;
+  }
+
+  @Override
+  public User getPrincipal() {
+    return user;
+  }
+
+  @Override
+  public boolean isAuthenticated() {
+    return authenticated;
+  }
+
+  @Override
+  public void setAuthenticated(boolean authenticated) throws IllegalArgumentException {
+    this.authenticated = authenticated;
+  }
+
+  @Override
+  public String getName() {
+    return user.getUserName();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
new file mode 100644
index 0000000..d061c69
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
@@ -0,0 +1,329 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.security.authorization.jwt;
+
+import com.google.inject.Inject;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWSObject;
+import com.nimbusds.jose.JWSVerifier;
+import com.nimbusds.jose.crypto.RSASSAVerifier;
+import com.nimbusds.jwt.SignedJWT;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
+import org.apache.ambari.server.security.authorization.User;
+import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.ambari.server.security.authorization.Users;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.*;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.security.interfaces.RSAPublicKey;
+import java.text.ParseException;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Filter is used to validate JWT token and authenticate user.
+ * It is also responsive for creating user in local Ambari database for further management
+ */
+public class JwtAuthenticationFilter implements Filter {
+  Logger LOG = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
+
+  private final JwtAuthenticationProperties jwtProperties;
+
+  private String originalUrlQueryParam = "originalUrl";
+  private String authenticationProviderUrl = null;
+  private RSAPublicKey publicKey = null;
+  private List<String> audiences = null;
+  private String cookieName = "hadoop-jwt";
+
+  private boolean ignoreFailure = true;
+  private AuthenticationEntryPoint entryPoint;
+  private Users users;
+
+  @Inject
+  public JwtAuthenticationFilter(Configuration configuration, AuthenticationEntryPoint entryPoint, Users users) {
+    this.entryPoint = entryPoint;
+    this.users = users;
+    jwtProperties = configuration.getJwtProperties();
+    loadJwtProperties();
+  }
+
+  public JwtAuthenticationFilter(JwtAuthenticationProperties jwtProperties, AuthenticationEntryPoint entryPoint,
+                                 Users users) {
+    this.jwtProperties = jwtProperties;
+    this.entryPoint = entryPoint;
+    this.users = users;
+    loadJwtProperties();
+  }
+
+  @Override
+  public void init(FilterConfig filterConfig) throws ServletException {
+
+  }
+
+  @Override
+  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+
+    if (jwtProperties != null && isAuthenticationRequired()) {
+      HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+      HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
+
+      String serializedJWT = getJWTFromCookie(httpServletRequest);
+      if (serializedJWT != null) {
+        SignedJWT jwtToken = null;
+        try {
+          jwtToken = SignedJWT.parse(serializedJWT);
+          boolean valid = validateToken(jwtToken);
+
+          if (valid) {
+            String userName = jwtToken.getJWTClaimsSet().getSubject();
+            User user = users.getUser(userName, UserType.JWT);
+            if (user == null) {
+              // create user in local database on first login, usually we cannot fetch all users
+              // from external authentication provider (as we do during ldap-sync process)
+              users.createUser(userName, null, UserType.JWT, true, false);
+              user = users.getUser(userName, UserType.JWT);
+            }
+
+            Collection<AmbariGrantedAuthority> userAuthorities =
+                users.getUserAuthorities(user.getUserName(), user.getUserType());
+
+            JwtAuthentication token = new JwtAuthentication(jwtToken, user, userAuthorities);
+            token.setAuthenticated(true);
+
+            SecurityContextHolder.getContext().setAuthentication(token);
+
+
+          } else {
+            LOG.warn("JWT authentication failed");
+            if (ignoreFailure) {
+              filterChain.doFilter(servletRequest, servletResponse);
+            } else {
+              //used to indicate authentication failure, not used here as we have more than one filter
+              entryPoint.commence(httpServletRequest, httpServletResponse, new BadCredentialsException("Invalid JWT " +
+                  "token"));
+            }
+          }
+
+
+
+        } catch (ParseException e) {
+          LOG.warn("Unable to parse the JWT token", e);
+        }
+      }
+    }
+
+    filterChain.doFilter(servletRequest, servletResponse);
+  }
+
+  private void loadJwtProperties() {
+    if (jwtProperties != null) {
+      authenticationProviderUrl = jwtProperties.getAuthenticationProviderUrl();
+      publicKey = jwtProperties.getPublicKey();
+      audiences = jwtProperties.getAudiences();
+      cookieName = jwtProperties.getCookieName();
+      originalUrlQueryParam = jwtProperties.getOriginalUrlQueryParam();
+    }
+  }
+
+  /**
+   * Do not try to validate JWT if user already authenticated via other provider
+   * @return true, if JWT validation required
+   */
+  private boolean isAuthenticationRequired() {
+    Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
+    return !(existingAuth != null && existingAuth.isAuthenticated()) || existingAuth instanceof JwtAuthentication;
+  }
+
+  /**
+   * Encapsulate the acquisition of the JWT token from HTTP cookies within the
+   * request.
+   *
+   * @param req servlet request to get the JWT token from
+   * @return serialized JWT token
+   */
+  protected String getJWTFromCookie(HttpServletRequest req) {
+    String serializedJWT = null;
+    Cookie[] cookies = req.getCookies();
+    String userName = null;
+    if (cookies != null) {
+      for (Cookie cookie : cookies) {
+        if (cookieName.equals(cookie.getName())) {
+          LOG.info(cookieName
+              + " cookie has been found and is being processed");
+          serializedJWT = cookie.getValue();
+          break;
+        }
+      }
+    }
+    return serializedJWT;
+  }
+  /**
+   * Create the URL to be used for authentication of the user in the absence of
+   * a JWT token within the incoming request.
+   *
+   * @param request for getting the original request URL
+   * @return url to use as login url for redirect
+   */
+  protected String constructLoginURL(HttpServletRequest request) {
+    String delimiter = "?";
+    if (authenticationProviderUrl.contains("?")) {
+      delimiter = "&";
+    }
+    String loginURL = authenticationProviderUrl + delimiter
+        + originalUrlQueryParam + "="
+        + request.getRequestURL().toString();
+    return loginURL;
+  }
+
+  /**
+   * This method provides a single method for validating the JWT for use in
+   * request processing. It provides for the override of specific aspects of
+   * this implementation through submethods used within but also allows for the
+   * override of the entire token validation algorithm.
+   *
+   * @param jwtToken the token to validate
+   * @return true if valid
+   */
+  protected boolean validateToken(SignedJWT jwtToken) {
+    boolean sigValid = validateSignature(jwtToken);
+    if (!sigValid) {
+      LOG.warn("Signature could not be verified");
+    }
+    boolean audValid = validateAudiences(jwtToken);
+    if (!audValid) {
+      LOG.warn("Audience validation failed.");
+    }
+    boolean expValid = validateExpiration(jwtToken);
+    if (!expValid) {
+      LOG.info("Expiration validation failed.");
+    }
+
+    return sigValid && audValid && expValid;
+  }
+
+  /**
+   * Verify the signature of the JWT token in this method. This method depends
+   * on the public key that was established during init based upon the
+   * provisioned public key. Override this method in subclasses in order to
+   * customize the signature verification behavior.
+   *
+   * @param jwtToken the token that contains the signature to be validated
+   * @return valid true if signature verifies successfully; false otherwise
+   */
+  protected boolean validateSignature(SignedJWT jwtToken) {
+    boolean valid = false;
+    if (JWSObject.State.SIGNED == jwtToken.getState()) {
+      LOG.debug("JWT token is in a SIGNED state");
+      if (jwtToken.getSignature() != null) {
+        LOG.debug("JWT token signature is not null");
+        try {
+          JWSVerifier verifier = new RSASSAVerifier(publicKey);
+          if (jwtToken.verify(verifier)) {
+            valid = true;
+            LOG.debug("JWT token has been successfully verified");
+          } else {
+            LOG.warn("JWT signature verification failed.");
+          }
+        } catch (JOSEException je) {
+          LOG.warn("Error while validating signature", je);
+        }
+      }
+    }
+    return valid;
+  }
+
+  /**
+   * Validate whether any of the accepted audience claims is present in the
+   * issued token claims list for audience. Override this method in subclasses
+   * in order to customize the audience validation behavior.
+   *
+   * @param jwtToken
+   *          the JWT token where the allowed audiences will be found
+   * @return true if an expected audience is present, otherwise false
+   */
+  protected boolean validateAudiences(SignedJWT jwtToken) {
+    boolean valid = false;
+    try {
+      List<String> tokenAudienceList = jwtToken.getJWTClaimsSet()
+          .getAudience();
+      // if there were no expected audiences configured then just
+      // consider any audience acceptable
+      if (audiences == null) {
+        valid = true;
+      } else {
+        // if any of the configured audiences is found then consider it
+        // acceptable
+        boolean found = false;
+        for (String aud : tokenAudienceList) {
+          if (audiences.contains(aud)) {
+            LOG.debug("JWT token audience has been successfully validated");
+            valid = true;
+            break;
+          }
+        }
+        if (!valid) {
+          LOG.warn("JWT audience validation failed.");
+        }
+      }
+    } catch (ParseException pe) {
+      LOG.warn("Unable to parse the JWT token.", pe);
+    }
+    return valid;
+  }
+
+  /**
+   * Validate that the expiration time of the JWT token has not been violated.
+   * If it has then throw an AuthenticationException. Override this method in
+   * subclasses in order to customize the expiration validation behavior.
+   *
+   * @param jwtToken the token that contains the expiration date to validate
+   * @return valid true if the token has not expired; false otherwise
+   */
+  protected boolean validateExpiration(SignedJWT jwtToken) {
+    boolean valid = false;
+    try {
+      Date expires = jwtToken.getJWTClaimsSet().getExpirationTime();
+      if (expires != null && new Date().before(expires)) {
+        LOG.debug("JWT token expiration date has been "
+            + "successfully validated");
+        valid = true;
+      } else {
+        LOG.warn("JWT expiration date validation failed.");
+      }
+    } catch (ParseException pe) {
+      LOG.warn("JWT expiration date validation failed.", pe);
+    }
+    return valid;
+  }
+
+  @Override
+  public void destroy() {
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationProperties.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationProperties.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationProperties.java
new file mode 100644
index 0000000..d237a95
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationProperties.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.security.authorization.jwt;
+
+import java.security.interfaces.RSAPublicKey;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Class describes parameters of external JWT authentication provider
+ */
+public class JwtAuthenticationProperties {
+  private String authenticationProviderUrl = null;
+  private RSAPublicKey publicKey = null;
+  private List<String> audiences = null;
+  private String cookieName = "hadoop-jwt";
+  private String originalUrlQueryParam = null;
+
+  public String getAuthenticationProviderUrl() {
+    return authenticationProviderUrl;
+  }
+
+  public void setAuthenticationProviderUrl(String authenticationProviderUrl) {
+    this.authenticationProviderUrl = authenticationProviderUrl;
+  }
+
+  public RSAPublicKey getPublicKey() {
+    return publicKey;
+  }
+
+  public void setPublicKey(RSAPublicKey publicKey) {
+    this.publicKey = publicKey;
+  }
+
+  public List<String> getAudiences() {
+    return audiences;
+  }
+
+  public void setAudiences(List<String> audiences) {
+    this.audiences = audiences;
+  }
+
+  public void setAudiencesString(String audiencesString) {
+    if (audiencesString != null) {
+      // parse into the list
+      String[] audArray = audiencesString.split(",");
+      audiences = new ArrayList<String>();
+      Collections.addAll(audiences, audArray);
+    } else {
+      audiences = null;
+    }
+  }
+
+  public String getCookieName() {
+    return cookieName;
+  }
+
+  public void setCookieName(String cookieName) {
+    this.cookieName = cookieName;
+  }
+
+  public String getOriginalUrlQueryParam() {
+    return originalUrlQueryParam;
+  }
+
+  public void setOriginalUrlQueryParam(String originalUrlQueryParam) {
+    this.originalUrlQueryParam = originalUrlQueryParam;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/CertificateUtils.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/CertificateUtils.java b/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/CertificateUtils.java
new file mode 100644
index 0000000..8a4b2c4
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/CertificateUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.security.encryption;
+
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
+
+/**
+ * Utility class containing methods to works with certificates
+ */
+public class CertificateUtils {
+  private static final Logger LOG = LoggerFactory.getLogger(CertificateUtils.class);
+
+  /**
+   * Get RSA public key from X.509 certificate file
+   * @param filePath path to certificate file
+   * @return RSA public key
+   * @throws IOException
+   * @throws CertificateException
+   */
+  public static RSAPublicKey getPublicKeyFromFile(String filePath) throws IOException, CertificateException {
+    String pemString = FileUtils.readFileToString(new File(filePath));
+    return getPublicKeyFromString(pemString);
+  }
+
+  /**
+   * Get RSA public key from X.509 certificate string (full crt file content, including header and footer)
+   * @param certificateString certificate string
+   * @return RSA public key
+   * @throws CertificateException
+   * @throws UnsupportedEncodingException
+   */
+  public static RSAPublicKey getPublicKeyFromString(String certificateString)
+    throws CertificateException, UnsupportedEncodingException {
+
+    CertificateFactory fact = CertificateFactory.getInstance("X.509");
+    ByteArrayInputStream is = new ByteArrayInputStream(
+      certificateString.getBytes("UTF8"));
+
+    X509Certificate cer = (X509Certificate) fact.generateCertificate(is);
+    return (RSAPublicKey)cer.getPublicKey();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog220.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog220.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog220.java
index 804d97b..8e0aebb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog220.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog220.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.upgrade;
 
 import java.sql.SQLException;
 
+import com.google.inject.Provider;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.orm.DBAccessor.DBColumnInfo;
 import org.apache.ambari.server.orm.dao.DaoUtils;
@@ -29,13 +30,18 @@ import org.slf4j.LoggerFactory;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 
+import javax.persistence.EntityManager;
+
 
 /**
  * Upgrade catalog for version 2.2.0.
  */
 public class UpgradeCatalog220 extends AbstractUpgradeCatalog {
   private static final String HOST_ROLE_COMMAND_TABLE = "host_role_command";
+  private static final String USERS_TABLE = "users";
+
   private static final String HOST_ID_COL = "host_id";
+  private static final String USER_TYPE_COL = "user_type";
 
   @Inject
   DaoUtils daoUtils;
@@ -85,6 +91,12 @@ public class UpgradeCatalog220 extends AbstractUpgradeCatalog {
   protected void executeDDLUpdates() throws AmbariException, SQLException {
 
     dbAccessor.alterColumn(HOST_ROLE_COMMAND_TABLE, new DBColumnInfo(HOST_ID_COL, Long.class, null, null, true));
+    dbAccessor.addColumn(USERS_TABLE, new DBColumnInfo(USER_TYPE_COL, String.class, null, "LOCAL", true));
+
+    dbAccessor.executeQuery("UPDATE users SET user_type='LDAP' WHERE ldap_user=1");
+
+    dbAccessor.addUniqueConstraint(USERS_TABLE, "UNQ_users_0", "user_name", "user_type");
+
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/python/ambari-server.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari-server.py b/ambari-server/src/main/python/ambari-server.py
index 3ea608c..a0f12e0 100755
--- a/ambari-server/src/main/python/ambari-server.py
+++ b/ambari-server/src/main/python/ambari-server.py
@@ -36,12 +36,14 @@ from ambari_server.serverUtils import is_server_runing, refresh_stack_hash
 from ambari_server.serverSetup import reset, setup, setup_jce_policy
 from ambari_server.serverUpgrade import upgrade, upgrade_stack, set_current
 from ambari_server.setupHttps import setup_https, setup_truststore
+from ambari_server.setupSso import setup_sso
 from ambari_server.hostUpdate import update_host_names
 from ambari_server.enableStack import enable_stack_version
 
 from ambari_server.setupActions import BACKUP_ACTION, LDAP_SETUP_ACTION, LDAP_SYNC_ACTION, PSTART_ACTION, \
   REFRESH_STACK_HASH_ACTION, RESET_ACTION, RESTORE_ACTION, UPDATE_HOST_NAMES_ACTION, SETUP_ACTION, SETUP_SECURITY_ACTION, \
-  START_ACTION, STATUS_ACTION, STOP_ACTION, UPGRADE_ACTION, UPGRADE_STACK_ACTION, SETUP_JCE_ACTION, SET_CURRENT_ACTION, ENABLE_STACK_ACTION
+  START_ACTION, STATUS_ACTION, STOP_ACTION, UPGRADE_ACTION, UPGRADE_STACK_ACTION, SETUP_JCE_ACTION, \
+  SET_CURRENT_ACTION, ENABLE_STACK_ACTION, SETUP_SSO_ACTION
 from ambari_server.setupSecurity import setup_ldap, sync_ldap, setup_master_key, setup_ambari_krb5_jaas
 from ambari_server.userInput import get_validated_string_input
 
@@ -507,6 +509,7 @@ def create_user_action_map(args, options):
     LDAP_SETUP_ACTION: UserAction(setup_ldap),
     SETUP_SECURITY_ACTION: UserActionRestart(setup_security, options),
     REFRESH_STACK_HASH_ACTION: UserAction(refresh_stack_hash_action),
+    SETUP_SSO_ACTION: UserActionRestart(setup_sso, options)
   }
   return action_map
 
@@ -529,7 +532,8 @@ def create_user_action_map(args, options):
         BACKUP_ACTION: UserActionPossibleArgs(backup, [1, 2], args),
         RESTORE_ACTION: UserActionPossibleArgs(restore, [1, 2], args),
         UPDATE_HOST_NAMES_ACTION: UserActionPossibleArgs(update_host_names, [2], args, options),
-        ENABLE_STACK_ACTION: UserAction(enable_stack, options, args)
+        ENABLE_STACK_ACTION: UserAction(enable_stack, options, args),
+        SETUP_SSO_ACTION: UserActionRestart(setup_sso, options)
       }
   return action_map
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/python/ambari_server/setupActions.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/setupActions.py b/ambari-server/src/main/python/ambari_server/setupActions.py
index ec2d788..5989020 100644
--- a/ambari-server/src/main/python/ambari_server/setupActions.py
+++ b/ambari-server/src/main/python/ambari_server/setupActions.py
@@ -30,6 +30,7 @@ REFRESH_STACK_HASH_ACTION = "refresh-stack-hash"
 STATUS_ACTION = "status"
 SETUP_HTTPS_ACTION = "setup-https"
 LDAP_SETUP_ACTION = "setup-ldap"
+SETUP_SSO_ACTION = "setup-sso"
 LDAP_SYNC_ACTION = "sync-ldap"
 SET_CURRENT_ACTION = "set-current"
 SETUP_GANGLIA_HTTPS_ACTION = "setup-ganglia-https"
@@ -39,4 +40,4 @@ UPDATE_HOST_NAMES_ACTION = "update-host-names"
 BACKUP_ACTION = "backup"
 RESTORE_ACTION = "restore"
 SETUP_JCE_ACTION = "setup-jce"
-ENABLE_STACK_ACTION = "enable-stack"
+ENABLE_STACK_ACTION = "enable-stack"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/python/ambari_server/setupSso.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/setupSso.py b/ambari-server/src/main/python/ambari_server/setupSso.py
new file mode 100644
index 0000000..a7c9108
--- /dev/null
+++ b/ambari-server/src/main/python/ambari_server/setupSso.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+'''
+
+from ambari_commons.os_utils import is_root, run_os_command, copy_file, set_file_permissions, remove_file
+from ambari_commons.exceptions import FatalException, NonFatalException
+from ambari_commons.logging_utils import get_silent, print_warning_msg, print_error_msg
+from ambari_server.userInput import get_validated_string_input, get_prompt_default, read_password, get_YN_input
+
+from ambari_server.serverConfiguration import get_ambari_properties, get_value_from_properties, update_properties, \
+  store_password_file
+
+JWT_AUTH_ENBABLED = "authentication.jwt.enabled"
+JWT_AUTH_PROVIDER_URL = "authentication.jwt.providerUrl"
+JWT_PUBLIC_KEY = "authentication.jwt.publicKey"
+JWT_AUDIENCES = "authentication.jwt.audiences"
+JWT_COOKIE_NAME = "authentication.jwt.cookieName"
+JWT_ORIGINAL_URL_QUERY_PARAM = "authentication.jwt.originalUrlParamName"
+
+JWT_COOKIE_NAME_DEFAULT = "hadoop-jwt"
+JWT_ORIGINAL_URL_QUERY_PARAM_DEFAULT = "originalUrl"
+
+REGEX_ANYTHING = ".*"
+
+JWT_PUBLIC_KEY_FILENAME = "jwt-cert.crt"
+JWT_PUBLIC_KEY_HEADER = "-----BEGIN CERTIFICATE-----\n"
+JWT_PUBLIC_KEY_FOOTER = "\n-----END CERTIFICATE-----"
+
+
+
+def setup_sso(args):
+  if not is_root():
+    err = 'ambari-server setup-sso should be run with ' \
+          'root-level privileges'
+    raise FatalException(4, err)
+  if not get_silent():
+    properties = get_ambari_properties()
+
+    must_setup_params = False
+
+    sso_enabled = properties.get_property(JWT_AUTH_ENBABLED).lower() in ['true']
+
+    if sso_enabled:
+      if get_YN_input("Do you want to disable SSO authentication [y/n] (n)?", False):
+        properties.process_pair(JWT_AUTH_ENBABLED, "false")
+    else:
+      if get_YN_input("Do you want to configure SSO authentication [y/n] (y)?", True):
+        must_setup_params = True
+      else:
+        return False
+
+    if must_setup_params:
+      provider_url = properties.get_property(JWT_AUTH_PROVIDER_URL)
+      provider_url = get_validated_string_input("Provider URL [URL] ({}):".format(provider_url),
+                                                provider_url,
+                                                REGEX_ANYTHING,
+                                                "Invalid provider URL",
+                                                False)
+      properties.process_pair(JWT_AUTH_PROVIDER_URL, provider_url)
+
+      cert_string = properties.get_property(JWT_PUBLIC_KEY)
+      cert_string = get_validated_string_input("Public Certificate [BASE64] ({}):".format('stored' if cert_string else 'empty'),
+                                               cert_string,
+                                               REGEX_ANYTHING,
+                                               "Invalid public certificae string",
+                                               False)
+
+      if get_YN_input("Do you want to configure advanced properties [y/n] (n) ?", False):
+        cookie_name = get_value_from_properties(properties, JWT_COOKIE_NAME, JWT_COOKIE_NAME_DEFAULT)
+        cookie_name = get_validated_string_input("JWT Cookie name ({}):".format(cookie_name),
+                                                 cookie_name,
+                                                 REGEX_ANYTHING,
+                                                 "Invalid cookie name",
+                                                 False)
+        properties.process_pair(JWT_COOKIE_NAME, cookie_name)
+
+        audiences = properties.get_property(JWT_AUDIENCES)
+        audiences = get_validated_string_input("JWT audiences list (comma-separated), empty for any ({}):".format(audiences),
+                                               audiences,
+                                               REGEX_ANYTHING,
+                                               "Invalid value",
+                                               False)
+        properties.process_pair(JWT_AUDIENCES, audiences)
+
+        # TODO not required for now as we support Knox only
+        # orig_query_param = get_value_from_properties(JWT_ORIGINAL_URL_QUERY_PARAM, JWT_ORIGINAL_URL_QUERY_PARAM_DEFAULT)
+        # orig_query_param = get_validated_string_input("Original URL query parameter name ({}):".format(orig_query_param),
+        #                                               orig_query_param,
+        #                                               REGEX_ANYTHING,
+        #                                               "Invalid value",
+        #                                               False)
+        # properties.process_pair(JWT_ORIGINAL_URL_QUERY_PARAM, orig_query_param)
+
+      full_cert = JWT_PUBLIC_KEY_HEADER + cert_string + JWT_PUBLIC_KEY_FOOTER
+      cert_path = store_password_file(full_cert, JWT_PUBLIC_KEY_FILENAME)
+      properties.process_pair(JWT_PUBLIC_KEY, cert_path)
+
+    update_properties(properties)
+
+    pass
+  else:
+    warning = "setup-sso is not enabled in silent mode."
+    raise NonFatalException(warning)
+
+  pass

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index c00e46f..bd44418 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -196,6 +196,7 @@ CREATE TABLE users (
   principal_id BIGINT NOT NULL,
   create_time TIMESTAMP DEFAULT NOW(),
   ldap_user INTEGER NOT NULL DEFAULT 0,
+  user_type VARCHAR(255) NOT NULL DEFAULT 'LOCAL',
   user_name VARCHAR(255) NOT NULL,
   user_password VARCHAR(255),
   active INTEGER NOT NULL DEFAULT 1,
@@ -649,7 +650,7 @@ CREATE TABLE topology_logical_task (
 );
 
 -- altering tables by creating unique constraints----------
-ALTER TABLE users ADD CONSTRAINT UNQ_users_0 UNIQUE (user_name, ldap_user);
+ALTER TABLE users ADD CONSTRAINT UNQ_users_0 UNIQUE (user_name, user_type);
 ALTER TABLE groups ADD CONSTRAINT UNQ_groups_0 UNIQUE (group_name, ldap_group);
 ALTER TABLE members ADD CONSTRAINT UNQ_members_0 UNIQUE (group_id, user_id);
 ALTER TABLE clusterconfig ADD CONSTRAINT UQ_config_type_tag UNIQUE (cluster_id, type_name, version_tag);

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index 3cac618..fe7a8b3 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -187,6 +187,7 @@ CREATE TABLE users (
   create_time TIMESTAMP NULL,
   ldap_user NUMBER(10) DEFAULT 0,
   user_name VARCHAR2(255) NULL,
+  user_type VARCHAR(255) DEFAULT 'LOCAL',
   user_password VARCHAR2(255) NULL,
   active INTEGER DEFAULT 1 NOT NULL,
   active_widget_layouts VARCHAR2(1024) DEFAULT NULL,
@@ -638,7 +639,7 @@ CREATE TABLE topology_logical_task (
 );
 
 --------altering tables by creating unique constraints----------
-ALTER TABLE users ADD CONSTRAINT UNQ_users_0 UNIQUE (user_name, ldap_user);
+ALTER TABLE users ADD CONSTRAINT UNQ_users_0 UNIQUE (user_name, user_type);
 ALTER TABLE groups ADD CONSTRAINT UNQ_groups_0 UNIQUE (group_name, ldap_group);
 ALTER TABLE members ADD CONSTRAINT UNQ_members_0 UNIQUE (group_id, user_id);
 ALTER TABLE clusterconfig ADD CONSTRAINT UQ_config_type_tag UNIQUE (cluster_id, type_name, version_tag);

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index 2bcfb9a..382dd74 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -195,12 +195,12 @@ CREATE TABLE users (
   principal_id BIGINT NOT NULL,
   ldap_user INTEGER NOT NULL DEFAULT 0,
   user_name VARCHAR(255) NOT NULL,
+  user_type VARCHAR(255) NOT NULL DEFAULT 'LOCAL',
   create_time TIMESTAMP DEFAULT NOW(),
   user_password VARCHAR(255),
   active INTEGER NOT NULL DEFAULT 1,
   active_widget_layouts VARCHAR(1024) DEFAULT NULL,
-  PRIMARY KEY (user_id),
-  UNIQUE (ldap_user, user_name));
+  PRIMARY KEY (user_id));
 
 CREATE TABLE groups (
   group_id INTEGER,
@@ -643,6 +643,7 @@ CREATE TABLE topology_logical_task (
 );
 
 --------altering tables by creating unique constraints----------
+ALTER TABLE users ADD CONSTRAINT UNQ_users_0 UNIQUE (user_name, user_type);
 ALTER TABLE clusterconfig ADD CONSTRAINT UQ_config_type_tag UNIQUE (cluster_id, type_name, version_tag);
 ALTER TABLE clusterconfig ADD CONSTRAINT UQ_config_type_version UNIQUE (cluster_id, type_name, version);
 ALTER TABLE hosts ADD CONSTRAINT UQ_hosts_host_name UNIQUE (host_name);

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
index 56dff9b..cdca43f 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
@@ -222,12 +222,12 @@ CREATE TABLE ambari.users (
   principal_id BIGINT NOT NULL,
   ldap_user INTEGER NOT NULL DEFAULT 0,
   user_name VARCHAR(255) NOT NULL,
+  user_type VARCHAR(255) NOT NULL DEFAULT 'LOCAL',
   create_time TIMESTAMP DEFAULT NOW(),
   user_password VARCHAR(255),
   active INTEGER NOT NULL DEFAULT 1,
   active_widget_layouts VARCHAR(1024) DEFAULT NULL,
-  PRIMARY KEY (user_id),
-  UNIQUE (ldap_user, user_name));
+  PRIMARY KEY (user_id));
 GRANT ALL PRIVILEGES ON TABLE ambari.users TO :username;
 
 CREATE TABLE ambari.groups (
@@ -722,6 +722,7 @@ CREATE TABLE ambari.topology_logical_task (
 GRANT ALL PRIVILEGES ON TABLE ambari.topology_logical_task TO :username;
 
 --------altering tables by creating unique constraints----------
+ALTER TABLE ambari.users ADD CONSTRAINT UNQ_users_0 UNIQUE (user_name, user_type);
 ALTER TABLE ambari.clusterconfig ADD CONSTRAINT UQ_config_type_tag UNIQUE (cluster_id, type_name, version_tag);
 ALTER TABLE ambari.clusterconfig ADD CONSTRAINT UQ_config_type_version UNIQUE (cluster_id, type_name, version);
 ALTER TABLE ambari.hosts ADD CONSTRAINT UQ_hosts_host_name UNIQUE (host_name);

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
index 1cc83ed..4e16658 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
@@ -186,6 +186,7 @@ CREATE TABLE users (
   create_time TIMESTAMP DEFAULT NOW(),
   ldap_user INTEGER NOT NULL DEFAULT 0,
   user_name VARCHAR(255) NOT NULL,
+  user_type VARCHAR(255) NOT NULL DEFAULT 'LOCAL',
   user_password VARCHAR(255),
   active INTEGER NOT NULL DEFAULT 1,
   active_widget_layouts VARCHAR(1024) DEFAULT NULL,
@@ -639,7 +640,7 @@ CREATE TABLE topology_logical_task (
 );
 
 -- altering tables by creating unique constraints----------
-ALTER TABLE users ADD CONSTRAINT UNQ_users_0 UNIQUE (user_name, ldap_user);
+ALTER TABLE users ADD CONSTRAINT UNQ_users_0 UNIQUE (user_name, user_type);
 ALTER TABLE groups ADD CONSTRAINT UNQ_groups_0 UNIQUE (group_name, ldap_group);
 ALTER TABLE members ADD CONSTRAINT UNQ_members_0 UNIQUE (group_id, user_id);
 ALTER TABLE clusterconfig ADD CONSTRAINT UQ_config_type_tag UNIQUE (cluster_id, type_name, version_tag);

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
index 4b4b0d4..5c1a6db 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -207,15 +207,12 @@ CREATE TABLE users (
   principal_id BIGINT NOT NULL,
   ldap_user INTEGER NOT NULL DEFAULT 0,
   user_name VARCHAR(255) NOT NULL,
+  user_type VARCHAR(255) NOT NULL DEFAULT 'LOCAL',
   create_time DATETIME DEFAULT GETDATE(),
   user_password VARCHAR(255),
   active INTEGER NOT NULL DEFAULT 1,
   active_widget_layouts VARCHAR(1024) DEFAULT NULL,
-  PRIMARY KEY CLUSTERED (user_id),
-  UNIQUE (
-    ldap_user,
-    user_name
-    )
+  PRIMARY KEY CLUSTERED (user_id)
   );
 
 CREATE TABLE groups (
@@ -755,7 +752,7 @@ CREATE TABLE topology_logical_task (
 
 -- altering tables by creating unique constraints----------
 --------altering tables to add constraints----------
-ALTER TABLE users ADD CONSTRAINT UNQ_users_0 UNIQUE (user_name, ldap_user);
+ALTER TABLE users ADD CONSTRAINT UNQ_users_0 UNIQUE (user_name, user_type);
 ALTER TABLE groups ADD CONSTRAINT UNQ_groups_0 UNIQUE (group_name, ldap_group);
 ALTER TABLE members ADD CONSTRAINT UNQ_members_0 UNIQUE (group_id, user_id);
 ALTER TABLE clusterconfig ADD CONSTRAINT UQ_config_type_tag UNIQUE (cluster_id, type_name, version_tag);

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json
index 727bdc7..4052ad2 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -165,6 +165,7 @@
         "Users/password",
         "Users/old_password",
         "Users/ldap_user",
+        "Users/user_type",
         "Users/active",
         "Users/groups",
         "Users/admin",

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml b/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
index 097e233..8b5bd97 100644
--- a/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
+++ b/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
@@ -24,9 +24,10 @@
 
   <http use-expressions="true"
         disable-url-rewriting="true" entry-point-ref="ambariEntryPoint">
-    <http-basic entry-point-ref="ambariEntryPoint"/>
+    <http-basic/>
     <intercept-url pattern="/**" access="isAuthenticated()"/>
-    <custom-filter ref="ambariAuthorizationFilter" after="BASIC_AUTH_FILTER"/>
+    <custom-filter ref="ambariJwtAuthenticationFilter" after="BASIC_AUTH_FILTER" />
+    <custom-filter ref="ambariAuthorizationFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
   </http>
 
   <!--<ldap-server id="ldapServer" root="dc=ambari,dc=apache,dc=org"/>-->

http://git-wip-us.apache.org/repos/asf/ambari/blob/40ec645a/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariErrorHandlerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariErrorHandlerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariErrorHandlerTest.java
index fb41f6e..8b4f99c 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariErrorHandlerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariErrorHandlerTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api;
 import com.google.gson.Gson;
 import com.google.gson.JsonSyntaxException;
 import com.sun.jersey.api.client.*;
+import org.apache.ambari.server.configuration.Configuration;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.servlet.DefaultServlet;
 import org.eclipse.jetty.servlet.ServletContextHandler;
@@ -51,13 +52,14 @@ public class AmbariErrorHandlerTest {
   @Test
   public void testErrorWithJetty() throws Exception {
     Server server = new Server(0);
+    Configuration configuration = new Configuration();
 
     ServletContextHandler root = new ServletContextHandler(server, "/",
       ServletContextHandler.SECURITY | ServletContextHandler.SESSIONS);
 
     root.addServlet(HelloServlet.class, "/hello");
     root.addServlet(DefaultServlet.class, "/");
-    root.setErrorHandler(new AmbariErrorHandler(gson));
+    root.setErrorHandler(new AmbariErrorHandler(gson, configuration));
 
     server.start();
 


Mime
View raw message