You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by mc...@apache.org on 2015/10/30 15:30:16 UTC

[50/50] [abbrv] nifi git commit: NIFI-655: - Creating an endpoint for returning the identity of the current user. - Updating the LoginAuthenticationFilter.

NIFI-655:
- Creating an endpoint for returning the identity of the current user.
- Updating the LoginAuthenticationFilter.

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

Branch: refs/heads/NIFI-655
Commit: e7a5e1822163e065fb72c889fcad6f038807e9f7
Parents: a40e5a0
Author: Matt Gilman <ma...@gmail.com>
Authored: Fri Oct 30 10:11:03 2015 -0400
Committer: Matt Gilman <ma...@gmail.com>
Committed: Fri Oct 30 10:17:34 2015 -0400

----------------------------------------------------------------------
 .../org/apache/nifi/util/NiFiProperties.java    |   2 +-
 .../nifi/web/api/dto/LoginConfigurationDTO.java |  60 ++++++++++
 .../api/entity/LoginConfigurationEntity.java    |  43 +++++++
 .../org/apache/nifi/web/NiFiServiceFacade.java  |   8 ++
 .../web/NiFiWebApiSecurityConfiguration.java    |  10 +-
 .../nifi/web/StandardNiFiServiceFacade.java     |  23 ++++
 .../apache/nifi/web/api/ControllerResource.java |  49 ++++++++
 .../src/main/resources/nifi-web-api-context.xml |   1 +
 .../form/LoginAuthenticationFilter.java         | 119 +++++++++++++++----
 .../form/LoginAuthenticationProvider.java       |  53 ---------
 .../security/jwt/JwtAuthenticationFilter.java   |   2 +-
 .../token/LoginAuthenticationRequestToken.java  |  37 ------
 .../token/LoginAuthenticationToken.java         |  48 --------
 .../security/x509/X509AuthenticationFilter.java |   2 +-
 .../web/NiFiWebUiSecurityConfiguration.java     |  25 ----
 .../src/main/webapp/WEB-INF/pages/login.jsp     |  13 +-
 .../WEB-INF/partials/canvas/canvas-header.jsp   |   2 +-
 .../WEB-INF/partials/login/login-form.jsp       |  28 +++++
 .../partials/login/registration-form.jsp        |  19 +++
 .../nifi-web-ui/src/main/webapp/css/canvas.css  |   1 +
 .../webapp/js/nf/canvas/nf-canvas-header.js     |  16 ++-
 .../src/main/webapp/js/nf/canvas/nf-canvas.js   |  14 ++-
 .../src/main/webapp/js/nf/login/nf-login.js     |  44 ++++++-
 23 files changed, 400 insertions(+), 219 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
index 32ed663..809dd09 100644
--- a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
+++ b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
@@ -484,7 +484,7 @@ public class NiFiProperties extends Properties {
             return new File(value);
         }
     }
-    
+
     /**
      * @return the user authorities file
      */

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LoginConfigurationDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LoginConfigurationDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LoginConfigurationDTO.java
new file mode 100644
index 0000000..e4452c0
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LoginConfigurationDTO.java
@@ -0,0 +1,60 @@
+/*
+ * 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.nifi.web.api.dto;
+
+import com.wordnik.swagger.annotations.ApiModelProperty;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Details for the login configuration.
+ */
+@XmlType(name = "loginConfig")
+public class LoginConfigurationDTO {
+
+    private Boolean supportsLogin;
+    private Boolean supportsRegistration;
+
+    /**
+     * @return Indicates whether or not this NiFi supports user login.
+     */
+    @ApiModelProperty(
+            value = "Indicates whether or not this NiFi supports user login.",
+            readOnly = true
+    )
+    public Boolean getSupportsLogin() {
+        return supportsLogin;
+    }
+
+    public void setSupportsLogin(Boolean supportsLogin) {
+        this.supportsLogin = supportsLogin;
+    }
+
+    /**
+     * @return If this NiFi supports login, indicates whether or not registration is supported.
+     */
+    @ApiModelProperty(
+            value = "If this NiFi supports login, indicates whether or not registration is supported.",
+            readOnly = true
+    )
+    public Boolean getSupportsRegistration() {
+        return supportsRegistration;
+    }
+
+    public void setSupportsRegistration(Boolean supportsRegistration) {
+        this.supportsRegistration = supportsRegistration;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LoginConfigurationEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LoginConfigurationEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LoginConfigurationEntity.java
new file mode 100644
index 0000000..da62d6f
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LoginConfigurationEntity.java
@@ -0,0 +1,43 @@
+/*
+ * 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.nifi.web.api.entity;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import org.apache.nifi.web.api.dto.LoginConfigurationDTO;
+
+/**
+ * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a LoginConfigurationDTO.
+ */
+@XmlRootElement(name = "loginConfigurationEntity")
+public class LoginConfigurationEntity extends Entity {
+
+    private LoginConfigurationDTO config;
+
+    /**
+     * The LoginConfigurationDTO that is being serialized.
+     *
+     * @return The LoginConfigurationDTO object
+     */
+    public LoginConfigurationDTO getConfig() {
+        return config;
+    }
+
+    public void setConfig(LoginConfigurationDTO config) {
+        this.config = config;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
index f4d5821..3c64a02 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
@@ -43,6 +43,7 @@ import org.apache.nifi.web.api.dto.ProcessGroupDTO;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
 import org.apache.nifi.web.api.dto.ComponentHistoryDTO;
 import org.apache.nifi.web.api.dto.ControllerServiceReferencingComponentDTO;
+import org.apache.nifi.web.api.dto.LoginConfigurationDTO;
 import org.apache.nifi.web.api.dto.PropertyDescriptorDTO;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupPortDTO;
@@ -178,6 +179,13 @@ public interface NiFiServiceFacade {
     ControllerConfigurationDTO getControllerConfiguration();
 
     /**
+     * Gets the login configuration for this controller.
+     *
+     * @return The login configuration
+     */
+    LoginConfigurationDTO getLoginConfiguration();
+
+    /**
      * Updates the configuration for this controller.
      *
      * @param revision Revision to compare with current base revision

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiSecurityConfiguration.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiSecurityConfiguration.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiSecurityConfiguration.java
index 7aeb105..dcf2e71 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiSecurityConfiguration.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiSecurityConfiguration.java
@@ -24,7 +24,6 @@ import org.apache.nifi.web.security.NiFiAuthenticationProvider;
 import org.apache.nifi.web.security.anonymous.NiFiAnonymousUserFilter;
 import org.apache.nifi.web.security.NiFiAuthenticationEntryPoint;
 import org.apache.nifi.web.security.form.LoginAuthenticationFilter;
-import org.apache.nifi.web.security.form.LoginAuthenticationProvider;
 import org.apache.nifi.web.security.jwt.JwtAuthenticationFilter;
 import org.apache.nifi.web.security.jwt.JwtAuthenticationProvider;
 import org.apache.nifi.web.security.jwt.JwtService;
@@ -37,6 +36,7 @@ import org.apache.nifi.web.security.x509.ocsp.OcspCertificateValidator;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.AuthenticationProvider;
 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
@@ -75,6 +75,7 @@ public class NiFiWebApiSecurityConfiguration extends WebSecurityConfigurerAdapte
                 .authenticationEntryPoint(new NiFiAuthenticationEntryPoint())
                 .and()
                 .authorizeRequests()
+                .antMatchers(HttpMethod.GET, "/controller/login/config").permitAll()
                 .anyRequest().fullyAuthenticated()
                 .and()
                 .sessionManagement()
@@ -113,15 +114,10 @@ public class NiFiWebApiSecurityConfiguration extends WebSecurityConfigurerAdapte
 
     @Override
     protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-        final LoginAuthenticationProvider baseLoginAuthenticationProvider = new LoginAuthenticationProvider();
-        baseLoginAuthenticationProvider.setLoginIdentityProvider(loginIdentityProvider);
-
-        final AuthenticationProvider loginAuthenticationProvider = new NiFiAuthenticationProvider(baseLoginAuthenticationProvider, userDetailsService);
         final AuthenticationProvider x509AuthenticationProvider = new NiFiAuthenticationProvider(new X509AuthenticationProvider(), userDetailsService);
         final AuthenticationProvider jwtAuthenticationProvider = new NiFiAuthenticationProvider(new JwtAuthenticationProvider(), userDetailsService);
 
         auth
-                .authenticationProvider(loginAuthenticationProvider)
                 .authenticationProvider(x509AuthenticationProvider)
                 .authenticationProvider(jwtAuthenticationProvider);
     }
@@ -129,7 +125,7 @@ public class NiFiWebApiSecurityConfiguration extends WebSecurityConfigurerAdapte
     private LoginAuthenticationFilter buildLoginFilter(final String url) {
         final LoginAuthenticationFilter loginFilter = new LoginAuthenticationFilter(url);
         loginFilter.setJwtService(jwtService);
-        loginFilter.setLoginIdentityProvider(loginIdentityProvider);
+        loginFilter.setUserDetailsService(userDetailsService);
         loginFilter.setPrincipalExtractor(new SubjectDnX509PrincipalExtractor());
         loginFilter.setCertificateExtractor(new X509CertificateExtractor());
         return loginFilter;

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
index 75cd140..b4fcfb3 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
@@ -153,6 +153,7 @@ import org.apache.nifi.web.util.SnippetUtils;
 
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.authentication.LoginIdentityProvider;
 import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.components.Validator;
 import org.apache.nifi.controller.ReportingTaskNode;
@@ -163,6 +164,7 @@ import org.apache.nifi.controller.service.ControllerServiceState;
 import org.apache.nifi.reporting.ComponentType;
 import org.apache.nifi.web.api.dto.ControllerServiceDTO;
 import org.apache.nifi.web.api.dto.ControllerServiceReferencingComponentDTO;
+import org.apache.nifi.web.api.dto.LoginConfigurationDTO;
 import org.apache.nifi.web.api.dto.PropertyDescriptorDTO;
 import org.apache.nifi.web.api.dto.ReportingTaskDTO;
 import org.apache.nifi.web.api.dto.status.ClusterProcessGroupStatusDTO;
@@ -205,6 +207,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     // administrative services
     private AuditService auditService;
     private UserService userService;
+    private LoginIdentityProvider loginIdentityProvider;
 
     // cluster manager
     private WebClusterManager clusterManager;
@@ -2348,6 +2351,22 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
+    public LoginConfigurationDTO getLoginConfiguration() {
+        final LoginConfigurationDTO loginConfiguration = new LoginConfigurationDTO();
+
+        // specify whether login/registration should be supported
+        if (loginIdentityProvider == null) {
+            loginConfiguration.setSupportsLogin(false);
+            loginConfiguration.setSupportsRegistration(false);
+        } else {
+            loginConfiguration.setSupportsLogin(true);
+            loginConfiguration.setSupportsRegistration(loginIdentityProvider.supportsRegistration());
+        }
+
+        return loginConfiguration;
+    }
+
+    @Override
     public ControllerConfigurationDTO getControllerConfiguration() {
         ControllerConfigurationDTO controllerConfig = new ControllerConfigurationDTO();
         controllerConfig.setName(controllerFacade.getName());
@@ -3407,6 +3426,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
         this.snippetUtils = snippetUtils;
     }
 
+    public void setLoginIdentityProvider(LoginIdentityProvider loginIdentityProvider) {
+        this.loginIdentityProvider = loginIdentityProvider;
+    }
+
     private boolean isPrimaryNode(String nodeId) {
         final Node primaryNode = clusterManager.getPrimaryNode();
         return (primaryNode != null && primaryNode.getNodeId().getId().equals(nodeId));

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
index 31b256e..1a23626 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
@@ -78,8 +78,10 @@ import org.apache.nifi.web.api.request.ClientIdParameter;
 import org.apache.nifi.web.api.request.IntegerParameter;
 import org.apache.nifi.web.api.request.LongParameter;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.web.api.dto.LoginConfigurationDTO;
 import org.apache.nifi.web.api.entity.ControllerServiceTypesEntity;
 import org.apache.nifi.web.api.entity.IdentityEntity;
+import org.apache.nifi.web.api.entity.LoginConfigurationEntity;
 import org.apache.nifi.web.api.entity.ReportingTaskTypesEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
 
@@ -655,6 +657,53 @@ public class ControllerResource extends ApplicationResource {
     }
 
     /**
+     * Retrieves the login configuration for this NiFi.
+     *
+     * @param httpServletRequest the servlet request
+     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
+     * @return A loginConfigurationEntity
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @Path("/login/config")
+    @ApiOperation(
+            value = "Retrieves the login configuration for this NiFi",
+            response = LoginConfigurationEntity.class
+    )
+    public Response getLoginConfig(
+            @Context HttpServletRequest httpServletRequest,
+            @ApiParam(
+                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
+                    required = false
+            )
+            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
+
+        // replicate if cluster manager
+        if (properties.isClusterManager()) {
+            return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
+        }
+
+        final LoginConfigurationDTO loginConfig = serviceFacade.getLoginConfiguration();
+
+        // only support login/registration when running securely
+        loginConfig.setSupportsLogin(loginConfig.getSupportsLogin() && httpServletRequest.isSecure());
+        loginConfig.setSupportsRegistration(loginConfig.getSupportsRegistration() && httpServletRequest.isSecure());
+
+        // create the revision
+        final RevisionDTO revision = new RevisionDTO();
+        revision.setClientId(clientId.getClientId());
+
+        // create the response entity
+        final LoginConfigurationEntity entity = new LoginConfigurationEntity();
+        entity.setRevision(revision);
+        entity.setConfig(loginConfig);
+
+        // generate the response
+        return clusterContext(generateOkResponse(entity)).build();
+    }
+
+    /**
      * Retrieves the configuration for this NiFi.
      *
      * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
index e034baa..96c3f2b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
@@ -122,6 +122,7 @@
         <property name="optimisticLockingManager" ref="webOptimisticLockingManager"/>
         <property name="dtoFactory" ref="dtoFactory"/>
         <property name="clusterManager" ref="clusterManager"/>
+        <property name="loginIdentityProvider" ref="loginIdentityProvider"/>
     </bean>
 
     <!-- depecrated -->

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/form/LoginAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/form/LoginAuthenticationFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/form/LoginAuthenticationFilter.java
index 565b56b..5b9e6e0 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/form/LoginAuthenticationFilter.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/form/LoginAuthenticationFilter.java
@@ -26,16 +26,21 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.apache.nifi.authentication.LoginCredentials;
 import org.apache.nifi.authentication.LoginIdentityProvider;
+import org.apache.nifi.util.StringUtils;
 import org.apache.nifi.web.security.ProxiedEntitiesUtils;
 import org.apache.nifi.web.security.jwt.JwtService;
 import org.apache.nifi.web.security.token.NiFiAuthenticationRequestToken;
-import org.apache.nifi.web.security.token.LoginAuthenticationRequestToken;
 import org.apache.nifi.web.security.x509.X509CertificateExtractor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
+import org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException;
 import org.springframework.security.web.authentication.preauth.x509.X509PrincipalExtractor;
 
 /**
@@ -45,11 +50,13 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
 
     private static final Logger logger = LoggerFactory.getLogger(LoginAuthenticationFilter.class);
 
+    private AuthenticationUserDetailsService<NiFiAuthenticationRequestToken> userDetailsService;
+
     private X509CertificateExtractor certificateExtractor;
     private X509PrincipalExtractor principalExtractor;
 
-    private JwtService jwtService;
     private LoginIdentityProvider loginIdentityProvider;
+    private JwtService jwtService;
 
     public LoginAuthenticationFilter(final String defaultFilterProcessesUrl) {
         super(defaultFilterProcessesUrl);
@@ -64,34 +71,70 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
         if (!request.isSecure()) {
             return null;
         }
-        
-        // look for a certificate
-        final X509Certificate certificate = certificateExtractor.extractClientCertificate(request);
-
-        // ensure the cert was found
-        if (certificate != null) {
-            // extract the principal
-            Object certificatePrincipal = principalExtractor.extractPrincipal(certificate);
-            final String principal = ProxiedEntitiesUtils.formatProxyDn(certificatePrincipal.toString());
-
-            final List<String> proxyChain = ProxiedEntitiesUtils.buildProxyChain(request, principal);
-            return new NiFiAuthenticationRequestToken(proxyChain);
+
+        // look for the credentials in the request
+        final LoginCredentials credentials = getLoginCredentials(request);
+
+        // if the credentials were not part of the request, attempt to log in with the certificate in the request
+        if (credentials == null) {
+            // look for a certificate
+            final X509Certificate certificate = certificateExtractor.extractClientCertificate(request);
+
+            if (certificate == null) {
+                throw new PreAuthenticatedCredentialsNotFoundException("Unable to extract client certificate after processing request with no login credentials specified.");
+            }
+
+            // authorize the proxy if necessary
+            final String principal = extractPrincipal(certificate);
+            authorizeProxyIfNecessary(ProxiedEntitiesUtils.buildProxyChain(request, principal));
+
+            final LoginCredentials preAuthenticatedCredentials = new LoginCredentials(principal, null);
+            return new LoginAuthenticationToken(preAuthenticatedCredentials);
         } else {
-            // if there were no certificate or no principal, defer to the login provider
-            final LoginCredentials credentials = getLoginCredentials(request);
+            // look for a certificate
+            final X509Certificate certificate = certificateExtractor.extractClientCertificate(request);
+
+            // if there was a certificate with this request see if it was proxying an end user request
+            if (certificate != null) {
+                // authorize the proxy if necessary
+                final String principal = extractPrincipal(certificate);
+                authorizeProxyIfNecessary(ProxiedEntitiesUtils.buildProxyChain(request, principal));
+            }
 
-            // if unable to authenticate return null
-            if (credentials == null) {
-                return null;
+            if (loginIdentityProvider.authenticate(credentials)) {
+                return new LoginAuthenticationToken(credentials);
+            } else {
+                throw new BadCredentialsException("User could not be authenticated with the configured identity provider.");
             }
+        }
+    }
 
-            final List<String> proxyChain = ProxiedEntitiesUtils.buildProxyChain(request, credentials.getUsername());
-            return new LoginAuthenticationRequestToken(proxyChain, credentials);
+    private void authorizeProxyIfNecessary(final List<String> proxyChain) throws AuthenticationException {
+        if (proxyChain.size() > 1) {
+            try {
+                userDetailsService.loadUserDetails(new NiFiAuthenticationRequestToken(proxyChain));
+            } catch (final UsernameNotFoundException unfe) {
+                // if a username not found exception was thrown, the proxies were authorized and now
+                // we can issue a new ID token to the end user
+            }
         }
     }
 
+    private String extractPrincipal(final X509Certificate certificate) {
+        // extract the principal
+        final Object certificatePrincipal = principalExtractor.extractPrincipal(certificate);
+        return ProxiedEntitiesUtils.formatProxyDn(certificatePrincipal.toString());
+    }
+
     private LoginCredentials getLoginCredentials(HttpServletRequest request) {
-        return new LoginCredentials(request.getParameter("username"), request.getParameter("password"));
+        final String username = request.getParameter("username");
+        final String password = request.getParameter("password");
+
+        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
+            return null;
+        } else {
+            return new LoginCredentials(username, password);
+        }
     }
 
     @Override
@@ -112,6 +155,34 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
         out.println("Invalid username/password");
     }
 
+    /**
+     * This is an Authentication Token for logging in. Once a user is authenticated, they can be issues an ID token.
+     */
+    public static class LoginAuthenticationToken extends AbstractAuthenticationToken {
+
+        final LoginCredentials credentials;
+
+        public LoginAuthenticationToken(final LoginCredentials credentials) {
+            super(null);
+            setAuthenticated(true);
+            this.credentials = credentials;
+        }
+
+        public LoginCredentials getLoginCredentials() {
+            return credentials;
+        }
+
+        @Override
+        public Object getCredentials() {
+            return credentials.getPassword();
+        }
+
+        @Override
+        public Object getPrincipal() {
+            return credentials.getUsername();
+        }
+    }
+
     public void setJwtService(JwtService jwtService) {
         this.jwtService = jwtService;
     }
@@ -128,4 +199,8 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
         this.principalExtractor = principalExtractor;
     }
 
+    public void setUserDetailsService(AuthenticationUserDetailsService<NiFiAuthenticationRequestToken> userDetailsService) {
+        this.userDetailsService = userDetailsService;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/form/LoginAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/form/LoginAuthenticationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/form/LoginAuthenticationProvider.java
deleted file mode 100644
index 16e5288..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/form/LoginAuthenticationProvider.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.nifi.web.security.form;
-
-import org.apache.nifi.authentication.LoginIdentityProvider;
-import org.apache.nifi.web.security.token.LoginAuthenticationRequestToken;
-import org.apache.nifi.web.security.token.LoginAuthenticationToken;
-import org.springframework.security.authentication.AuthenticationProvider;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-
-/**
- *
- */
-public class LoginAuthenticationProvider implements AuthenticationProvider {
-
-    private LoginIdentityProvider loginIdentityProvider;
-
-    @Override
-    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
-        final LoginAuthenticationRequestToken loginAuthenticationToken = (LoginAuthenticationRequestToken) authentication;
-
-        if (loginIdentityProvider.authenticate(loginAuthenticationToken.getLoginCredentials())) {
-            return new LoginAuthenticationToken(loginAuthenticationToken.getLoginCredentials());
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public boolean supports(Class<?> authentication) {
-        return LoginAuthenticationRequestToken.class.isAssignableFrom(authentication);
-    }
-
-    public void setLoginIdentityProvider(LoginIdentityProvider loginIdentityProvider) {
-        this.loginIdentityProvider = loginIdentityProvider;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationFilter.java
index a628ff6..380289d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationFilter.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationFilter.java
@@ -42,7 +42,7 @@ public class JwtAuthenticationFilter extends NiFiAuthenticationFilter {
         if (!request.isSecure()) {
             return null;
         }
-        
+
         final String principal = jwtService.getAuthentication(request);
         if (principal == null) {
             return null;

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/LoginAuthenticationRequestToken.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/LoginAuthenticationRequestToken.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/LoginAuthenticationRequestToken.java
deleted file mode 100644
index d1ca4d2..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/LoginAuthenticationRequestToken.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.nifi.web.security.token;
-
-import java.util.List;
-import org.apache.nifi.authentication.LoginCredentials;
-
-/**
- * This is an Authentication Token for requesting an ID token for accessing the NIFI REST API.
- */
-public class LoginAuthenticationRequestToken extends NiFiAuthenticationRequestToken {
-
-    final LoginCredentials credentials;
-
-    public LoginAuthenticationRequestToken(final List<String> proxyChain, final LoginCredentials credentials) {
-        super(proxyChain);
-        this.credentials = credentials;
-    }
-
-    public LoginCredentials getLoginCredentials() {
-        return credentials;
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/LoginAuthenticationToken.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/LoginAuthenticationToken.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/LoginAuthenticationToken.java
deleted file mode 100644
index 528b60b..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/LoginAuthenticationToken.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.nifi.web.security.token;
-
-import org.apache.nifi.authentication.LoginCredentials;
-import org.springframework.security.authentication.AbstractAuthenticationToken;
-
-/**
- * This is an Authentication Token for logging in. Once a user is authenticated, they can be issues an ID token.
- */
-public class LoginAuthenticationToken extends AbstractAuthenticationToken {
-
-    final LoginCredentials credentials;
-
-    public LoginAuthenticationToken(final LoginCredentials credentials) {
-        super(null);
-        setAuthenticated(true);
-        this.credentials = credentials;
-    }
-
-    public LoginCredentials getLoginCredentials() {
-        return credentials;
-    }
-
-    @Override
-    public Object getCredentials() {
-        return credentials.getPassword();
-    }
-
-    @Override
-    public Object getPrincipal() {
-        return credentials.getUsername();
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationFilter.java
index e57a5ac..a52afcc 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationFilter.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationFilter.java
@@ -50,7 +50,7 @@ public class X509AuthenticationFilter extends NiFiAuthenticationFilter {
         if (!request.isSecure()) {
             return null;
         }
-        
+
         // extract the cert
         X509Certificate certificate = certificateExtractor.extractClientCertificate(request);
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/java/org/apache/nifi/web/NiFiWebUiSecurityConfiguration.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/java/org/apache/nifi/web/NiFiWebUiSecurityConfiguration.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/java/org/apache/nifi/web/NiFiWebUiSecurityConfiguration.java
index 46b90d0..5a1bb67 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/java/org/apache/nifi/web/NiFiWebUiSecurityConfiguration.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/java/org/apache/nifi/web/NiFiWebUiSecurityConfiguration.java
@@ -16,16 +16,12 @@
  */
 package org.apache.nifi.web;
 
-import org.apache.nifi.web.security.form.LoginAuthenticationFilter;
-import org.apache.nifi.web.security.jwt.JwtService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
-import org.springframework.security.config.http.SessionCreationPolicy;
-import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 
 /**
  * NiFi Web Ui Security Config
@@ -38,32 +34,11 @@ public class NiFiWebUiSecurityConfiguration extends WebSecurityConfigurerAdapter
         super(true); // disable defaults
     }
 
-    private JwtService jwtService;
-
     @Override
     protected void configure(final HttpSecurity http) throws Exception {
-        http
-                .addFilterBefore(buildFormLoginFilter(), UsernamePasswordAuthenticationFilter.class)
-                .sessionManagement()
-                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
-    }
-
-    private LoginAuthenticationFilter buildFormLoginFilter() throws Exception {
-        final LoginAuthenticationFilter loginFilter = new LoginAuthenticationFilter("/token");
-        loginFilter.setJwtService(jwtService);
-        return loginFilter;
     }
 
     @Autowired
     public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
-        auth
-                .inMemoryAuthentication()
-                    .withUser("gilman").password("password").roles("USER");
     }
-
-    @Autowired
-    public void setJwtService(JwtService jwtService) {
-        this.jwtService = jwtService;
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/login.jsp
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/login.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/login.jsp
index c54f1fd..69c91e6 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/login.jsp
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/login.jsp
@@ -34,16 +34,7 @@
         ${nf.login.script.tags}
     </head>
     <body>
-        <form name="loginForm" action="token" method="post">
-            <legend>Please Login</legend>
-            <label for="username">Username</label>
-            <input type="text" id="username" name="username" value="${username}"/>
-            <br>
-            <label for="password">Password</label>
-            <input type="password" id="password" name="password"/>
-            <div class="form-actions">
-                <button type="submit" class="btn">Log in</button>
-            </div>
-        </form>
+        <jsp:include page="/WEB-INF/partials/login/login-form.jsp"/>
+        <jsp:include page="/WEB-INF/partials/login/registration-form.jsp"/>
     </body>
 </html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
index b4ae7d5..153ed21 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
@@ -50,7 +50,7 @@
             <li>
                 <span id="about-link" class="link">about</span>
             </li>
-            <li>
+            <li id="login-link-container">
                 <span id="login-link" class="link">login</span>
             </li>
         </ul>

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/login/login-form.jsp
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/login/login-form.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/login/login-form.jsp
new file mode 100644
index 0000000..889863e
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/login/login-form.jsp
@@ -0,0 +1,28 @@
+<%--
+ 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.
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<div id="login-form">
+    <legend>Please Login</legend>
+    <label for="username">Username</label>
+    <input type="text" id="username" name="username" value="${username}"/>
+    <br>
+    <label for="password">Password</label>
+    <input type="password" id="password" name="password"/>
+    <div class="form-actions">
+        <button id="login-button" type="submit" class="btn">Log in</button>
+    </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/login/registration-form.jsp
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/login/registration-form.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/login/registration-form.jsp
new file mode 100644
index 0000000..56808e2
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/login/registration-form.jsp
@@ -0,0 +1,19 @@
+<%--
+ 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.
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<div id="registration-form">
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
index a8866ad..1c66609 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
@@ -42,4 +42,5 @@
 @import url(settings.css);
 @import url(about.css);
 @import url(message-pane.css);
+@import url(login.css);
 @import url(status-history.css);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-header.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-header.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-header.js
index e4f8977..653d895 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-header.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-header.js
@@ -32,7 +32,7 @@ nf.CanvasHeader = (function () {
         /**
          * Initialize the canvas header.
          */
-        init: function () {
+        init: function (supportsLogin) {
             // mouse over for the reporting link
             nf.Common.addHoverEffect('#reporting-link', 'reporting-link', 'reporting-link-hover').click(function () {
                 nf.Shell.showPage('summary');
@@ -138,11 +138,15 @@ nf.CanvasHeader = (function () {
             $('#help-link').click(function () {
                 nf.Shell.showPage(config.urls.helpDocument);
             });
-            
-            // login link
-            $('#login-link').click(function () {
-                nf.Shell.showPage('login', false);
-            });
+
+            if (supportsLogin === true) {
+                // login link
+                $('#login-link').click(function () {
+                    nf.Shell.showPage('login', false);
+                });
+            } else {
+                $('#login-link-container').css('display', 'none');
+            }
 
             // initialize the new template dialog
             $('#new-template-dialog').modal({

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
index 33f116e..190c7a7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
@@ -64,6 +64,7 @@ nf.Canvas = (function () {
             banners: '../nifi-api/controller/banners',
             controller: '../nifi-api/controller',
             controllerConfig: '../nifi-api/controller/config',
+            loginConfig: '../nifi-api/controller/login/config',
             cluster: '../nifi-api/cluster',
             d3Script: 'js/d3/d3.min.js'
         }
@@ -1036,6 +1037,13 @@ nf.Canvas = (function () {
                 url: config.urls.controllerConfig,
                 dataType: 'json'
             });
+            
+            // get the login config
+            var loginXhr = $.ajax({
+                type: 'GET',
+                url: config.urls.loginConfig,
+                dataType: 'json'
+            });
 
             // create the deferred cluster request
             var isClusteredRequest = $.Deferred(function (deferred) {
@@ -1063,9 +1071,10 @@ nf.Canvas = (function () {
             });
 
             // ensure the authorities and config request is processed first
-            $.when(authoritiesXhr, configXhr).done(function (authoritiesResult, configResult) {
+            $.when(authoritiesXhr, configXhr, loginXhr).done(function (authoritiesResult, configResult, loginResult) {
                 var authoritiesResponse = authoritiesResult[0];
                 var configResponse = configResult[0];
+                var loginResponse = loginResult[0];
 
                 // set the user's authorities
                 nf.Common.setAuthorities(authoritiesResponse.authorities);
@@ -1076,6 +1085,7 @@ nf.Canvas = (function () {
 
                 // get the config details
                 var configDetails = configResponse.config;
+                var loginDetails = loginResponse.config;
 
                 // when both request complete, load the application
                 isClusteredRequest.done(function () {
@@ -1095,7 +1105,7 @@ nf.Canvas = (function () {
                         nf.ContextMenu.init();
                         nf.CanvasToolbar.init();
                         nf.CanvasToolbox.init();
-                        nf.CanvasHeader.init();
+                        nf.CanvasHeader.init(loginDetails.supportsLogin);
                         nf.GraphControl.init();
                         nf.Search.init();
                         nf.Settings.init();

http://git-wip-us.apache.org/repos/asf/nifi/blob/e7a5e182/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/login/nf-login.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/login/nf-login.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/login/nf-login.js
index a6d9b23..345d794 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/login/nf-login.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/login/nf-login.js
@@ -22,10 +22,40 @@ $(document).ready(function () {
 });
 
 nf.Login = (function () {
+    var loadControllerConfiguration = function () {
+        return $.ajax({
+            type: 'GET',
+            url: '../nifi-api/controller/login/config',
+            dataType: 'json'
+        });
+    };
+
     var initializePage = function () {
-        return $.Deferred(function (deferred) {
-            console.log('hello there');
-            deferred.resolve();
+        return loadControllerConfiguration().done(function (response) {
+            var config = response.config;
+            
+            if (config.supportsLogin === true) {
+                
+            }
+            
+            if (config.supportsRegistration === true) {
+                
+            }
+        });
+    };
+    
+    var login = function () {
+        var username = $('#username').val();
+        var password = $('#password').val();
+        
+        return $.ajax({
+            type: 'POST',
+            url: '../nifi-api/token',
+            data: {
+                'username': username,
+                'password': password
+            },
+            dataType: 'json'
         });
     };
 
@@ -34,7 +64,13 @@ nf.Login = (function () {
          * Initializes the login page.
          */
         init: function () {
-            initializePage().done(function () {
+            initializePage();
+            
+            // handle login click
+            $('#login-button').on('click', function () {
+                login().done(function (response) {
+                   console.log(response); 
+                });
             });
         }
     };