Repository: nifi Updated Branches: refs/heads/NIFI-655 221459286 -> 93aa09dac
NIFI-655: - Starting to add support for registration. - Creating registration form. Project: http://git-wip-us.apache.org/repos/asf/nifi/repo Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/93aa09da Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/93aa09da Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/93aa09da Branch: refs/heads/NIFI-655 Commit: 93aa09dace01c2abe301ee7781cc8ab54b48197a Parents: 2214592 Author: Matt Gilman <[email protected]> Authored: Wed Nov 4 22:03:52 2015 -0500 Committer: Matt Gilman <[email protected]> Committed: Wed Nov 4 22:03:52 2015 -0500 ---------------------------------------------------------------------- .../authentication/LoginIdentityProvider.java | 3 +- .../nifi/authorized/users/AuthorizedUsers.java | 8 + .../src/main/xsd/users.xsd | 7 +- .../FileAuthorizationProvider.java | 59 ++++- .../FileLoginIdentityProvider.java | 40 ++- .../org/apache/nifi/web/server/JettyServer.java | 9 +- .../web/NiFiWebApiSecurityConfiguration.java | 22 +- .../web/security/RegistrationStatusFilter.java | 26 +- .../form/LoginAuthenticationFilter.java | 111 ++++---- .../web/security/form/RegistrationFilter.java | 160 ++++++++++++ .../nifi/web/security/jwt/JwtService.java | 2 +- .../token/LoginAuthenticationToken.java | 48 ++++ .../src/main/webapp/WEB-INF/pages/login.jsp | 4 + .../WEB-INF/partials/login/login-form.jsp | 4 + .../partials/login/user-registration-form.jsp | 9 +- .../nifi-web-ui/src/main/webapp/css/login.css | 19 +- .../src/main/webapp/js/nf/canvas/nf-canvas.js | 18 +- .../src/main/webapp/js/nf/login/nf-login.js | 255 +++++++++++-------- 18 files changed, 569 insertions(+), 235 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/nifi-api/src/main/java/org/apache/nifi/authentication/LoginIdentityProvider.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authentication/LoginIdentityProvider.java b/nifi-api/src/main/java/org/apache/nifi/authentication/LoginIdentityProvider.java index 919d5b5..15a20a8 100644 --- a/nifi-api/src/main/java/org/apache/nifi/authentication/LoginIdentityProvider.java +++ b/nifi-api/src/main/java/org/apache/nifi/authentication/LoginIdentityProvider.java @@ -16,6 +16,7 @@ */ package org.apache.nifi.authentication; +import org.apache.nifi.authorization.exception.IdentityAlreadyExistsException; import org.apache.nifi.authorization.exception.ProviderCreationException; import org.apache.nifi.authorization.exception.ProviderDestructionException; @@ -36,7 +37,7 @@ public interface LoginIdentityProvider { * * @param credentials the login credentials */ - void register(LoginCredentials credentials); + void register(LoginCredentials credentials) throws IdentityAlreadyExistsException; /** * Authenticates the specified login credentials. http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorized-users/src/main/java/org/apache/nifi/authorized/users/AuthorizedUsers.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorized-users/src/main/java/org/apache/nifi/authorized/users/AuthorizedUsers.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorized-users/src/main/java/org/apache/nifi/authorized/users/AuthorizedUsers.java index e4be3f7..f19514e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorized-users/src/main/java/org/apache/nifi/authorized/users/AuthorizedUsers.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorized-users/src/main/java/org/apache/nifi/authorized/users/AuthorizedUsers.java @@ -207,6 +207,14 @@ public final class AuthorizedUsers { saveUsers(users); } + public synchronized void createOrUpdateUser(final FindUser finder, final CreateUser creator, final UpdateUser updater) { + try { + updateUser(finder, updater); + } catch (final UnknownIdentityException uie) { + createUser(creator); + } + } + public synchronized void updateUser(final FindUser finder, final UpdateUser updater) { // update the user final Users users = getUsers(); http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorized-users/src/main/xsd/users.xsd ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorized-users/src/main/xsd/users.xsd b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorized-users/src/main/xsd/users.xsd index b06ebc8..509f97b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorized-users/src/main/xsd/users.xsd +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorized-users/src/main/xsd/users.xsd @@ -48,7 +48,7 @@ <xs:complexType name="User"> <xs:complexContent> <xs:extension base="NiFiUser"> - <xs:attribute name="dn"> + <xs:attribute name="dn" use="required"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:minLength value="1"/> @@ -64,7 +64,7 @@ <xs:complexType name="LoginUser"> <xs:complexContent> <xs:extension base="NiFiUser"> - <xs:attribute name="username"> + <xs:attribute name="username" use="required"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:minLength value="1"/> @@ -72,7 +72,7 @@ </xs:restriction> </xs:simpleType> </xs:attribute> - <xs:attribute name="password"> + <xs:attribute name="password" use="required"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:minLength value="1"/> @@ -80,6 +80,7 @@ </xs:restriction> </xs:simpleType> </xs:attribute> + <xs:attribute name="pending" type="xs:boolean" use="required"/> </xs:extension> </xs:complexContent> </xs:complexType> http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorization-provider/src/main/java/org/apache/nifi/authorization/FileAuthorizationProvider.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorization-provider/src/main/java/org/apache/nifi/authorization/FileAuthorizationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorization-provider/src/main/java/org/apache/nifi/authorization/FileAuthorizationProvider.java index d06b85f..3400ce8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorization-provider/src/main/java/org/apache/nifi/authorization/FileAuthorizationProvider.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorization-provider/src/main/java/org/apache/nifi/authorization/FileAuthorizationProvider.java @@ -40,6 +40,7 @@ import org.apache.nifi.authorized.users.AuthorizedUsers.FindUsers; import org.apache.nifi.authorized.users.AuthorizedUsers.HasUser; import org.apache.nifi.authorized.users.AuthorizedUsers.UpdateUser; import org.apache.nifi.authorized.users.AuthorizedUsers.UpdateUsers; +import org.apache.nifi.user.generated.LoginUser; import org.apache.nifi.user.generated.NiFiUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -182,15 +183,37 @@ public class FileAuthorizationProvider implements AuthorityProvider { @Override public void addUser(final String dn, final String group) throws IdentityAlreadyExistsException, AuthorityAccessException { - authorizedUsers.createUser(new CreateUser() { + authorizedUsers.createOrUpdateUser(new FindUser() { @Override - public NiFiUser createUser() { - // ensure the user doesn't already exist - if (authorizedUsers.hasUser(new HasUserByIdentity(dn))) { - throw new IdentityAlreadyExistsException(String.format("User identity already exists: %s", dn)); + public NiFiUser findUser(final List<NiFiUser> users) throws UnknownIdentityException { + // attempt to get the user and ensure it was located + NiFiUser desiredUser = null; + for (final NiFiUser user : users) { + if (dn.equalsIgnoreCase(authorizedUsers.getUserIdentity(user))) { + desiredUser = user; + break; + } + } + + // user does not exist, will create + if (desiredUser == null) { + throw new UnknownIdentityException("This exception will trigger the creator to be invoked."); + } + + // user exists, verify its still pending + if (LoginUser.class.isAssignableFrom(desiredUser.getClass())) { + if (((LoginUser) desiredUser).isPending()) { + return desiredUser; + } } - // only support adding PreAuthenticatedUser's via this API - LoginUser's are added + // user exists and account is valid... no good + throw new IdentityAlreadyExistsException(String.format("User identity already exists: %s", dn)); + } + }, new CreateUser() { + @Override + public NiFiUser createUser() { + // only support adding PreAuthenticated User's via this API - LoginUser's are added // via the LoginIdentityProvider final ObjectFactory objFactory = new ObjectFactory(); final User newUser = objFactory.createUser(); @@ -212,6 +235,13 @@ public class FileAuthorizationProvider implements AuthorityProvider { return newUser; } + }, new UpdateUser() { + @Override + public void updateUser(final NiFiUser user) { + // only support updating Login Users's via this API - need to mark the account as non pending + LoginUser loginUser = (LoginUser) user; + loginUser.setPending(false); + } }); } @@ -306,6 +336,13 @@ public class FileAuthorizationProvider implements AuthorityProvider { this.properties = properties; } + private boolean isPendingLoginUser(final NiFiUser user) { + if (LoginUser.class.isAssignableFrom(user.getClass())) { + return ((LoginUser) user).isPending(); + } + return false; + } + public class HasUserByIdentity implements HasUser { private final String identity; @@ -324,7 +361,7 @@ public class FileAuthorizationProvider implements AuthorityProvider { // attempt to get the user and ensure it was located NiFiUser desiredUser = null; for (final NiFiUser user : users) { - if (identity.equalsIgnoreCase(authorizedUsers.getUserIdentity(user))) { + if (identity.equalsIgnoreCase(authorizedUsers.getUserIdentity(user)) && !isPendingLoginUser(user)) { desiredUser = user; break; } @@ -352,7 +389,7 @@ public class FileAuthorizationProvider implements AuthorityProvider { // attempt to get the user and ensure it was located NiFiUser desiredUser = null; for (final NiFiUser user : users) { - if (identity.equalsIgnoreCase(authorizedUsers.getUserIdentity(user))) { + if (identity.equalsIgnoreCase(authorizedUsers.getUserIdentity(user)) && !isPendingLoginUser(user)) { desiredUser = user; break; } @@ -366,7 +403,7 @@ public class FileAuthorizationProvider implements AuthorityProvider { } } - public static class FindUsersByGroup implements FindUsers { + public class FindUsersByGroup implements FindUsers { private final String group; @@ -384,7 +421,7 @@ public class FileAuthorizationProvider implements AuthorityProvider { // get all users with this group List<NiFiUser> userGroup = new ArrayList<>(); for (final NiFiUser user : users) { - if (group.equals(user.getGroup())) { + if (group.equals(user.getGroup()) && !isPendingLoginUser(user)) { userGroup.add(user); } } @@ -419,7 +456,7 @@ public class FileAuthorizationProvider implements AuthorityProvider { List<NiFiUser> userList = new ArrayList<>(); for (final NiFiUser user : users) { final String userIdentity = authorizedUsers.getUserIdentity(user); - if (copy.contains(userIdentity)) { + if (copy.contains(userIdentity) && !isPendingLoginUser(user)) { copy.remove(userIdentity); userList.add(user); } http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-identity-provider/src/main/java/org/apache/nifi/authentication/FileLoginIdentityProvider.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-identity-provider/src/main/java/org/apache/nifi/authentication/FileLoginIdentityProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-identity-provider/src/main/java/org/apache/nifi/authentication/FileLoginIdentityProvider.java index 6e72880..1f38f37 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-identity-provider/src/main/java/org/apache/nifi/authentication/FileLoginIdentityProvider.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-identity-provider/src/main/java/org/apache/nifi/authentication/FileLoginIdentityProvider.java @@ -19,9 +19,11 @@ package org.apache.nifi.authentication; import java.io.IOException; import java.util.List; import org.apache.nifi.authentication.annotation.LoginIdentityProviderContext; +import org.apache.nifi.authorization.exception.IdentityAlreadyExistsException; import org.apache.nifi.authorization.exception.ProviderCreationException; import org.apache.nifi.authorization.exception.ProviderDestructionException; import org.apache.nifi.authorized.users.AuthorizedUsers; +import org.apache.nifi.authorized.users.AuthorizedUsers.CreateUser; import org.apache.nifi.authorized.users.AuthorizedUsers.HasUser; import org.apache.nifi.user.generated.LoginUser; import org.apache.nifi.user.generated.NiFiUser; @@ -57,11 +59,43 @@ public class FileLoginIdentityProvider implements LoginIdentityProvider { @Override public boolean supportsRegistration() { - return false; + return true; } @Override - public void register(LoginCredentials credentials) { + public void register(final LoginCredentials credentials) throws IdentityAlreadyExistsException { + authorizedUsers.createUser(new CreateUser() { + @Override + public NiFiUser createUser() { + final HasUser hasUser = new HasUser() { + @Override + public boolean hasUser(List<NiFiUser> users) { + for (final NiFiUser user : users) { + // only consider LoginUsers + if (LoginUser.class.isAssignableFrom(user.getClass())) { + final LoginUser loginUser = (LoginUser) user; + if (credentials.getUsername().equals(loginUser.getUsername())) { + return true; + } + } + } + return false; + } + }; + + // if the user already exists + if (authorizedUsers.hasUser(hasUser)) { + throw new IdentityAlreadyExistsException(String.format("A user account for %s already exists.", credentials.getUsername())); + } + + // TODO - need to properly encrypt and hash the user password for storage + final LoginUser user = new LoginUser(); + user.setUsername(credentials.getUsername()); + user.setPassword(credentials.getPassword()); + user.setPending(true); + return user; + } + }); } @Override @@ -78,7 +112,7 @@ public class FileLoginIdentityProvider implements LoginIdentityProvider { if (LoginUser.class.isAssignableFrom(user.getClass())) { final LoginUser loginUser = (LoginUser) user; - // TODO - need to properly encrypt and hash password + // TODO - need to properly encrypt and hash the supplied password for comparison final String loginUserPassword = loginUser.getPassword(); if (credentials.getUsername().equals(loginUser.getUsername()) && credentials.getPassword().equals(loginUserPassword)) { return true; http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java index b2b3013..e8d2618 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java @@ -614,9 +614,12 @@ public class JettyServer implements NiFiServer { private SslContextFactory createSslContextFactory() { final SslContextFactory contextFactory = new SslContextFactory(); - // client auth - contextFactory.setWantClientAuth(true); - contextFactory.setNeedClientAuth(false); + // require client auth when not supporting login or anonymous access + if (StringUtils.isBlank(props.getProperty(NiFiProperties.SECURITY_USER_LOGIN_IDENTITY_PROVIDER)) && props.getAnonymousAuthorities().isEmpty()) { + contextFactory.setNeedClientAuth(true); + } else { + contextFactory.setWantClientAuth(true); + } /* below code sets JSSE system properties when values are provided */ // keystore properties http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/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 732c30e..3d7544e 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 @@ -25,6 +25,7 @@ import org.apache.nifi.web.security.anonymous.NiFiAnonymousUserFilter; import org.apache.nifi.web.security.NiFiAuthenticationEntryPoint; import org.apache.nifi.web.security.RegistrationStatusFilter; import org.apache.nifi.web.security.form.LoginAuthenticationFilter; +import org.apache.nifi.web.security.form.RegistrationFilter; import org.apache.nifi.web.security.jwt.JwtAuthenticationFilter; import org.apache.nifi.web.security.jwt.JwtService; import org.apache.nifi.web.security.node.NodeAuthorizedUserFilter; @@ -138,17 +139,22 @@ public class NiFiWebApiSecurityConfiguration extends WebSecurityConfigurerAdapte } private Filter buildRegistrationFilter(final String url) { - return null; + final RegistrationFilter registrationFilter = new RegistrationFilter(url); + registrationFilter.setJwtService(jwtService); + registrationFilter.setLoginIdentityProvider(loginIdentityProvider); + registrationFilter.setUserService(userService); + return registrationFilter; } private Filter buildRegistrationStatusFilter(final String url) { - final RegistrationStatusFilter registrationFilter = new RegistrationStatusFilter(url); - registrationFilter.setCertificateExtractor(certificateExtractor); - registrationFilter.setPrincipalExtractor(principalExtractor); - registrationFilter.setCertificateValidator(certificateValidator); - registrationFilter.setProperties(properties); - registrationFilter.setUserDetailsService(userDetailsService); - return registrationFilter; + final RegistrationStatusFilter registrationStatusFilter = new RegistrationStatusFilter(url); + registrationStatusFilter.setCertificateExtractor(certificateExtractor); + registrationStatusFilter.setPrincipalExtractor(principalExtractor); + registrationStatusFilter.setCertificateValidator(certificateValidator); + registrationStatusFilter.setProperties(properties); + registrationStatusFilter.setJwtService(jwtService); + registrationStatusFilter.setUserDetailsService(userDetailsService); + return registrationStatusFilter; } private NodeAuthorizedUserFilter buildNodeAuthorizedUserFilter() { http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/RegistrationStatusFilter.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/RegistrationStatusFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/RegistrationStatusFilter.java index 6a9e6ab..e914db5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/RegistrationStatusFilter.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/RegistrationStatusFilter.java @@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletResponse; import org.apache.nifi.authentication.LoginCredentials; import org.apache.nifi.util.NiFiProperties; import org.apache.nifi.util.StringUtils; +import org.apache.nifi.web.security.jwt.JwtService; import org.apache.nifi.web.security.token.NiFiAuthenticationRequestToken; import org.apache.nifi.web.security.x509.X509CertificateExtractor; import org.apache.nifi.web.security.x509.X509CertificateValidator; @@ -54,6 +55,7 @@ public class RegistrationStatusFilter extends AbstractAuthenticationProcessingFi private static final Logger logger = LoggerFactory.getLogger(RegistrationStatusFilter.class); private NiFiProperties properties; + private JwtService jwtService; private AuthenticationUserDetailsService<NiFiAuthenticationRequestToken> userDetailsService; private X509CertificateValidator certificateValidator; private X509CertificateExtractor certificateExtractor; @@ -78,21 +80,22 @@ public class RegistrationStatusFilter extends AbstractAuthenticationProcessingFi // if no certificate, just check the credentials if (certificate == null) { - final LoginCredentials credentials = getLoginCredentials(request); + final String principal = jwtService.getAuthentication(request); // ensure we have something we can work with (certificate or crendentials) - if (credentials == null) { + if (principal == null) { throw new BadCredentialsException("Unable to check registration status as no credentials were included with the request."); } // without a certificate, this is not a proxied request - final List<String> chain = Arrays.asList(credentials.getUsername()); + final List<String> chain = Arrays.asList(principal); // check authorization for this user checkAuthorization(chain); // no issues with authorization - return new RegistrationStatusAuthenticationToken(credentials); + final LoginCredentials tokenCredentials = new LoginCredentials(principal, null); + return new RegistrationStatusAuthenticationToken(tokenCredentials); } else { // we have a certificate so let's consider a proxy chain final String principal = extractPrincipal(certificate); @@ -147,17 +150,6 @@ public class RegistrationStatusFilter extends AbstractAuthenticationProcessingFi return ProxiedEntitiesUtils.formatProxyDn(certificatePrincipal.toString()); } - private LoginCredentials getLoginCredentials(HttpServletRequest request) { - 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 protected void successfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain, final Authentication authentication) throws IOException, ServletException { @@ -238,6 +230,10 @@ public class RegistrationStatusFilter extends AbstractAuthenticationProcessingFi } } + public void setJwtService(JwtService jwtService) { + this.jwtService = jwtService; + } + public void setCertificateValidator(X509CertificateValidator certificateValidator) { this.certificateValidator = certificateValidator; } http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/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 46e5b42..388b81e 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 @@ -16,6 +16,7 @@ */ package org.apache.nifi.web.security.form; +import org.apache.nifi.web.security.token.LoginAuthenticationToken; import java.io.IOException; import java.io.PrintWriter; import java.security.cert.CertificateExpiredException; @@ -36,7 +37,7 @@ import org.apache.nifi.web.security.x509.X509CertificateExtractor; import org.apache.nifi.web.security.x509.X509CertificateValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; @@ -84,42 +85,50 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF // look for a certificate final X509Certificate certificate = certificateExtractor.extractClientCertificate(request); + // if there is no certificate, look for an existing token if (certificate == null) { - throw new PreAuthenticatedCredentialsNotFoundException("Unable to extract client certificate after processing request with no login credentials specified."); - } - - // extract the principal - final String principal = extractPrincipal(certificate); - - try { - certificateValidator.validateClientCertificate(request, certificate); - } catch (CertificateExpiredException cee) { - final String message = String.format("Client certificate for (%s) is expired.", principal); - logger.info(message, cee); - if (logger.isDebugEnabled()) { - logger.debug("", cee); - } - return null; - } catch (CertificateNotYetValidException cnyve) { - final String message = String.format("Client certificate for (%s) is not yet valid.", principal); - logger.info(message, cnyve); - if (logger.isDebugEnabled()) { - logger.debug("", cnyve); + final String principal = jwtService.getAuthentication(request); + + if (principal == null) { + throw new AuthenticationCredentialsNotFoundException("Unable to issue token as issue token as no credentials were found in the request."); } - return null; - } catch (final Exception e) { - logger.info(e.getMessage()); - if (logger.isDebugEnabled()) { - logger.debug("", e); + + final LoginCredentials tokenCredentials = new LoginCredentials(principal, null); + return new LoginAuthenticationToken(tokenCredentials); + } else { + // extract the principal + final String principal = extractPrincipal(certificate); + + try { + certificateValidator.validateClientCertificate(request, certificate); + } catch (CertificateExpiredException cee) { + final String message = String.format("Client certificate for (%s) is expired.", principal); + logger.info(message, cee); + if (logger.isDebugEnabled()) { + logger.debug("", cee); + } + return null; + } catch (CertificateNotYetValidException cnyve) { + final String message = String.format("Client certificate for (%s) is not yet valid.", principal); + logger.info(message, cnyve); + if (logger.isDebugEnabled()) { + logger.debug("", cnyve); + } + return null; + } catch (final Exception e) { + logger.info(e.getMessage()); + if (logger.isDebugEnabled()) { + logger.debug("", e); + } + return null; } - return null; - } - // authorize the proxy if necessary - authorizeProxyIfNecessary(ProxiedEntitiesUtils.buildProxyChain(request, principal)); + // authorize the proxy if necessary + authorizeProxyIfNecessary(ProxiedEntitiesUtils.buildProxyChain(request, principal)); - final LoginCredentials preAuthenticatedCredentials = new LoginCredentials(principal, null); - return new LoginAuthenticationToken(preAuthenticatedCredentials); + final LoginCredentials preAuthenticatedCredentials = new LoginCredentials(principal, null); + return new LoginAuthenticationToken(preAuthenticatedCredentials); + } } else { if (loginIdentityProvider.authenticate(credentials)) { return new LoginAuthenticationToken(credentials); @@ -178,39 +187,15 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF @Override protected void unsuccessfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException failed) throws IOException, ServletException { - // set the response status - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType("text/plain"); - + final PrintWriter out = response.getWriter(); - out.println("Unable to authenticate."); - } - - /** - * 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(); + out.println(failed.getMessage()); + + if (failed instanceof BadCredentialsException || failed instanceof AuthenticationCredentialsNotFoundException) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } else { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); } } http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/form/RegistrationFilter.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/RegistrationFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/form/RegistrationFilter.java new file mode 100644 index 0000000..39adb68 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/form/RegistrationFilter.java @@ -0,0 +1,160 @@ +/* + * 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 java.io.IOException; +import java.io.PrintWriter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.nifi.admin.service.AccountDisabledException; +import org.apache.nifi.admin.service.AccountNotFoundException; +import org.apache.nifi.admin.service.AccountPendingException; +import org.apache.nifi.admin.service.AdministrationException; +import org.apache.nifi.admin.service.UserService; +import org.apache.nifi.authentication.LoginCredentials; +import org.apache.nifi.authentication.LoginIdentityProvider; +import org.apache.nifi.authorization.exception.IdentityAlreadyExistsException; +import org.apache.nifi.util.StringUtils; +import org.apache.nifi.web.security.jwt.JwtService; +import org.apache.nifi.web.security.token.LoginAuthenticationToken; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.AccountStatusException; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; + +/** + * Exchanges a successful login with the configured provider for a ID token for accessing the API. + */ +public class RegistrationFilter extends AbstractAuthenticationProcessingFilter { + + private static final Logger logger = LoggerFactory.getLogger(RegistrationFilter.class); + + private LoginIdentityProvider loginIdentityProvider; + private JwtService jwtService; + private UserService userService; + + public RegistrationFilter(final String defaultFilterProcessesUrl) { + super(defaultFilterProcessesUrl); + + // do not continue filter chain... simply exchanging authentication for token + setContinueChainBeforeSuccessfulAuthentication(false); + } + + @Override + public Authentication attemptAuthentication(final HttpServletRequest request, final HttpServletResponse response) throws AuthenticationException, IOException, ServletException { + // only suppport registration when running securely + if (!request.isSecure()) { + return null; + } + + // 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) { + throw new UsernameNotFoundException("User login credentials not found in request."); + } else { + try { + // attempt to register the user + loginIdentityProvider.register(credentials); + } catch (final IdentityAlreadyExistsException iaee) { + // if the identity already exists, try to create the nifi account request + } + + try { + // see if the account already exists so we're able to return the current status + userService.checkAuthorization(credentials.getUsername()); + + // account exists and is valid + throw new AccountStatusException(String.format("An account for %s already exists.", credentials.getUsername())) { + }; + } catch (AdministrationException ase) { + throw new AuthenticationServiceException(ase.getMessage(), ase); + } catch (AccountDisabledException | AccountPendingException e) { + throw new AccountStatusException(e.getMessage(), e) { + }; + } catch (AccountNotFoundException anfe) { + // create the pending user account + userService.createPendingUserAccount(credentials.getUsername(), request.getParameter("justification")); + + // create the login token + return new LoginAuthenticationToken(credentials); + } + } + } + + private LoginCredentials getLoginCredentials(HttpServletRequest request) { + 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 + protected void successfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain, final Authentication authentication) + throws IOException, ServletException { + + // generate JWT for response + jwtService.addToken(response, authentication); + + // mark as successful + response.setStatus(HttpServletResponse.SC_CREATED); + response.setContentType("text/plain"); + response.setContentLength(0); + } + + @Override + protected void unsuccessfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException failed) throws IOException, ServletException { + response.setContentType("text/plain"); + + final PrintWriter out = response.getWriter(); + out.println(failed.getMessage()); + + // set the appropriate response status + if (failed instanceof UsernameNotFoundException) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } else if (failed instanceof AccountStatusException) { + // account exists (maybe valid, pending, revoked) + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + } else { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } + + public void setJwtService(JwtService jwtService) { + this.jwtService = jwtService; + } + + public void setLoginIdentityProvider(LoginIdentityProvider loginIdentityProvider) { + this.loginIdentityProvider = loginIdentityProvider; + } + + public void setUserService(UserService userService) { + this.userService = userService; + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtService.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/JwtService.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtService.java index 1b4f41f..2012d69 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtService.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtService.java @@ -50,7 +50,7 @@ public class JwtService { * @param authentication The authentication to generate a token for */ public void addToken(final HttpServletResponse response, final Authentication authentication) { - // TODO : actually create real token + // TODO : actually create real token... in header or response body? // create a token the specified authentication String token = authentication.getName(); http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/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 new file mode 100644 index 0000000..528b60b --- /dev/null +++ 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 @@ -0,0 +1,48 @@ +/* + * 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/93aa09da/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 2c52032..925f93c 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 @@ -28,6 +28,7 @@ <link rel="stylesheet" href="js/jquery/ui-smoothness/jquery-ui-1.10.4.min.css" type="text/css" /> <script type="text/javascript" src="js/jquery/jquery-2.1.1.min.js"></script> <script type="text/javascript" src="js/jquery/jquery.count.js"></script> + <script type="text/javascript" src="js/jquery/jquery.center.js"></script> <script type="text/javascript" src="js/jquery/modal/jquery.modal.js?${project.version}"></script> <script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script> <script type="text/javascript" src="js/jquery/ui-smoothness/jquery-ui-1.10.4.min.js"></script> @@ -42,5 +43,8 @@ <jsp:include page="/WEB-INF/partials/login/nifi-registration-form.jsp"/> <jsp:include page="/WEB-INF/partials/login/login-submission.jsp"/> </div> + <jsp:include page="/WEB-INF/partials/ok-dialog.jsp"/> + <div id="faded-background"></div> + <div id="glass-pane"></div> </body> </html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/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 index f8f06f3..8480501 100644 --- 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 @@ -27,6 +27,10 @@ <div class="setting-name">Password</div> <div class="setting-field"> <input type="password" id="password"/> + <div id="create-account-message" class="hidden"> + <div style="font-style: italic;">Don't have an account?</div> + <div><span id="create-account-link" class="link">Create one</span> to request access.</div> + </div> </div> </div> </div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/login/user-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/user-registration-form.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/login/user-registration-form.jsp index 89517e4..7930e39 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/login/user-registration-form.jsp +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/login/user-registration-form.jsp @@ -16,18 +16,19 @@ --%> <%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %> <div id="user-registration-container" class="hidden"> - <div class="login-title">Log In</div> + <div class="login-title">Create Account</div> <div class="setting"> <div class="setting-name">Username</div> <div class="setting-field"> - <input type="text" id="username"/> + <input type="text" id="registration-username"/> </div> </div> <div class="setting"> <div class="setting-name">Password</div> <div class="setting-field"> - <input type="password" id="password"/><br/> - <input type="password" id="password-confirmation" placeholder="Confirm password"/> + <input type="password" id="registration-password" style="margin-bottom: 5px;"/> + <br/> + <input type="password" id="registration-password-confirmation" placeholder="Confirm password"/> </div> </div> </div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/login.css ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/login.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/login.css index e8466df..2fbe107 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/login.css +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/login.css @@ -19,7 +19,7 @@ Login Styles */ -body.login-body { +#login-contents-container { position: absolute; top: 0px; left: 0px; @@ -27,13 +27,8 @@ body.login-body { right: 0px; background: #fff url(../images/bg-error.png) left top no-repeat; font-family: Verdana, Geneva, sans-serif; - color: #191919; - z-index: 999999; -} - -#login-contents-container { - margin-top: 100px; - margin-left: 100px; + padding-top: 100px; + padding-left: 100px; } #login-message-title { @@ -61,6 +56,14 @@ body.login-body input, body.login-body textarea { width: 400px; } +#create-account-message { + margin-top: 2px; +} + +#create-account-link { + text-decoration: underline; +} + /* User Registration */ http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/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 b714c46..46578ab 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 @@ -1044,7 +1044,6 @@ nf.Canvas = (function () { dataType: 'json' }); - // load the identity and authorities for the current user var userXhr = $.Deferred(function(deferred) { $.when(authoritiesXhr, identityXhr).done(function (authoritiesResult, identityResult) { @@ -1059,22 +1058,15 @@ nf.Canvas = (function () { // if the user is logged, we want to determine if they were logged in using a certificate if (identityResponse.identity !== 'anonymous') { $('#current-user').text(identityResponse.identity).show(); - - // attempt to get a token for the current user without passing login credentials - $.ajax({ - type: 'GET', - url: config.urls.token - }).fail(function () { - // if this request succeeds, it means the user is logged in using their certificate. - // if this request fails, it means the user is logged in with login credentials so we want to render a logout button. + + // render the logout button if there is a token locally + if (nf.Storage.getItem('jwt') !== null) { $('#logout-link-container').show(); - }).always(function () { - deferred.resolve(); - }); + } } else { $('#current-user').text(nf.Canvas.ANONYMOUS_USER_TEXT).show(); - deferred.resolve(); } + deferred.resolve(); }).fail(function (xhr, status, error) { // there is no anonymous access and we don't know this user - open the login page which handles login/registration/etc if (xhr.status === 401) { http://git-wip-us.apache.org/repos/asf/nifi/blob/93aa09da/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 b844cba..4f4cb1d 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 @@ -44,131 +44,180 @@ nf.Login = (function () { // if this nifi supports registration, render the registration form if (supportsRegistration === true) { initializeUserRegistration(); - - // automatically include support for nifi registration initializeNiFiRegistration(); - // hide the submit justification title - $('#nifi-registration-title').hide(); + // show the create account message + $('#create-account-message').show(); - // update the submit button text - $('#login-submission-button').text('Create'); + // toggle between login and signup + $('#create-account-link').on('click', function () { + showUserRegistration(); + }); } - - // show the login form + }; + + var showLogin = function () { $('#login-container').show(); + $('#user-registration-container').hide(); + $('#nifi-registration-container').hide(); + $('#login-submission-button').text('Log in'); }; var initializeUserRegistration = function () { - - // show the user registration form - $('#user-registration-container').show(); }; var initializeNiFiRegistration = function () { $('#nifi-registration-justification').count({ charCountField: '#remaining-characters' }); + }; - // update the button text - $('#login-submission-button').text('Submit'); + var showUserRegistration = function () { + showNiFiRegistration(); + + $('#nifi-registration-title').hide(); + $('#user-registration-container').show(); + $('#login-submission-button').text('Create'); + }; - // show the nifi registration container + var showNiFiRegistration = function () { + $('#login-container').hide(); $('#nifi-registration-container').show(); + $('#login-submission-button').text('Submit'); }; var initializeSubmission = function () { - $('#login-submission-button').one('click', function () { + $('#login-submission-button').on('click', function () { if ($('#login-container').is(':visible')) { - var username = $('#username').val(); - var password = $('#password').val(); - - // login submit - $.ajax({ - type: 'POST', - url: '../nifi-api/token', - data: { - 'username': username, - 'password': password - } - }).done(function (response, status, xhr) { - var authorization = xhr.getResponseHeader('Authorization'); - var badToken = false; - - // ensure there was a token in the response - if (authorization) { - var tokens = authorization.split(/ /); - - // ensure the token is the appropriate length - if (tokens.length === 2) { - // store the jwt and reload the page - nf.Storage.setItem('jwt', tokens[1]); - - // reload as appropriate - if (top !== window) { - parent.window.location = '/nifi'; - } else { - window.location = '/nifi'; - } - return; - } else { - badToken = true; - } - } else { - badToken = true; - } - - if (badToken === true) { - $('#login-message-title').text('An unexpected error has occurred'); - $('#login-message').text('The id token could not be parsed.'); - - // update visibility - $('#login-container').hide(); - $('#login-submission-container').hide(); - $('#login-message-container').show(); - } - }).fail(function (xhr, status, error) { - $('#login-message-title').text('An unexpected error has occurred'); - $('#login-message').text(xhr.responseText); - - // update visibility - $('#login-container').hide(); - $('#login-submission-container').hide(); - $('#login-message-container').show(); - }); + login(); } else if ($('#user-registration-container').is(':visible')) { - var justification = $('#registration-justification').val(); - - // new user account submit + createUserAccount(); } else if ($('#nifi-registration-container').is(':visible')) { - // attempt to create the user account registration - $.ajax({ - type: 'POST', - url: config.urls.users, - data: { - 'justification': $('#registration-justification').val() - } - }).done(function (response) { - var markup = 'An administrator will process your request shortly.'; - if (isAnonymous === true) { - markup += '<br/><br/>In the meantime you can continue accessing anonymously.'; + submitJustification(); + } + }); + + $('#login-submission-container').show(); + }; + + var login = function () { + // login submit + $.ajax({ + type: 'POST', + url: config.urls.token, + data: { + 'username': $('#username').val(), + 'password': $('#password').val() + } + }).done(function (response, status, xhr) { + var authorization = xhr.getResponseHeader('Authorization'); + var badToken = false; + + // ensure there was a token in the response + if (authorization) { + var tokens = authorization.split(/ /); + + // ensure the token is the appropriate length + if (tokens.length === 2) { + // store the jwt and reload the page + nf.Storage.setItem('jwt', tokens[1]); + + // reload as appropriate + if (top !== window) { + parent.window.location = '/nifi'; + } else { + window.location = '/nifi'; } + return; + } else { + badToken = true; + } + } else { + badToken = true; + } - $('#login-message-title').text('Thanks!'); - $('#login-message').html(markup); - }).fail(function (xhr, status, error) { - $('#login-message-title').text('An unexpected error has occurred'); - $('#login-message').text(xhr.responseText); - }).always(function () { - // update form visibility - $('#nifi-registration-container').hide(); - $('#login-submission-container').hide(); - $('#login-message-container').show(); + if (badToken === true) { + $('#login-message-title').text('An unexpected error has occurred'); + $('#login-message').text('The user token could not be parsed.'); + + // update visibility + $('#login-container').hide(); + $('#login-submission-container').hide(); + $('#login-message-container').show(); + } + }).fail(function (xhr, status, error) { + if (xhr.status === 400) { + nf.Dialog.showOkDialog({ + dialogContent: nf.Common.escapeHtml(xhr.responseText), + overlayBackground: false }); + } else { + $('#login-message-title').text('Unable to log in'); + $('#login-message').text(xhr.responseText); + + // update visibility + $('#login-container').hide(); + $('#login-submission-container').hide(); + $('#login-message-container').show(); } }); + }; - $('#login-submission-container').show(); + var createUserAccount = function () { + // attempt to create the user account registration + $.ajax({ + type: 'POST', + url: config.urls.registration, + data: { + 'username': $('#registration-username').val(), + 'password': $('#registration-password').val(), + 'justification': $('#nifi-registration-justification').val() + } + }).done(function (response, status, xhr) { + var markup = 'An administrator will process your request shortly.'; + if (isAnonymous === true) { + markup += '<br/><br/>In the meantime you can continue accessing anonymously.'; + } + + $('#login-message-title').text('Thanks!'); + $('#login-message').html(markup); + }).fail(function (xhr, status, error) { + $('#login-message-title').text('Unable to create user account'); + $('#login-message').text(xhr.responseText); + }).always(function () { + // update form visibility + $('#user-registration-container').hide(); + $('#nifi-registration-container').hide(); + $('#login-submission-container').hide(); + $('#login-message-container').show(); + }); + }; + + var submitJustification = function () { + // attempt to create the nifi account registration + $.ajax({ + type: 'POST', + url: config.urls.users, + data: { + 'justification': $('#nifi-registration-justification').val() + } + }).done(function (response) { + var markup = 'An administrator will process your request shortly.'; + if (isAnonymous === true) { + markup += '<br/><br/>In the meantime you can continue accessing anonymously.'; + } + + $('#login-message-title').text('Thanks!'); + $('#login-message').html(markup); + }).fail(function (xhr, status, error) { + $('#login-message-title').text('Unable to submit justification'); + $('#login-message').text(xhr.responseText); + }).always(function () { + // update form visibility + $('#nifi-registration-container').hide(); + $('#login-submission-container').hide(); + $('#login-message-container').show(); + }); }; return { @@ -202,7 +251,7 @@ nf.Login = (function () { // request a token without including credentials, if successful then the user is using a certificate token.done(function () { - // the user is using a certificate, see if their account is active/pending/revoked/etc + // the user is using a certificate/token, see if their account is active/pending/revoked/etc $.ajax({ type: 'GET', url: config.urls.registrationStatus @@ -212,7 +261,6 @@ nf.Login = (function () { // account is active and good $('#login-message-title').text('Success'); $('#login-message').text('Your account is active and you are already logged in.'); - deferred.resolve(); }).fail(function (xhr, status, error) { if (xhr.status === 401) { // anonymous user and 401 means they need nifi registration @@ -228,6 +276,7 @@ nf.Login = (function () { $('#login-message').text(xhr.responseText); } } + }).always(function () { deferred.resolve(); }); }).fail(function () { @@ -248,7 +297,7 @@ nf.Login = (function () { if (xhr.status === 401) { // attempt to get a token for the current user without passing login credentials token.done(function () { - // 401 from identity request and 200 from token means they have a certificate but have not yet requested an account + // 401 from identity request and 200 from token means they have a certificate/token but have not yet requested an account needsNiFiRegistration = true; }).fail(function () { // no token granted, user needs to login with their credentials @@ -271,7 +320,7 @@ nf.Login = (function () { } }); }).promise(); - + var loginConfigXhr = $.ajax({ type: 'GET', url: config.urls.loginConfig, @@ -282,7 +331,7 @@ nf.Login = (function () { $.when(loginConfigXhr, pageStateInit).done(function (loginResult) { var loginResponse = loginResult[0]; var loginConfig = loginResponse.config; - + // if login is required, verify its supported if (loginConfig.supportsLogin === false && needsLogin === true) { $('#login-message-title').text('Access Denied'); @@ -290,13 +339,15 @@ nf.Login = (function () { showMessage = true; needsLogin = false; } - + if (showMessage === true) { initializeMessage(); } else if (needsLogin === true) { initializeLogin(loginConfig.supportsRegistration); + showLogin(); } else if (needsNiFiRegistration === true) { initializeNiFiRegistration(); + showNiFiRegistration(); } if (needsLogin === true || needsNiFiRegistration === true) {
