NIFI-655:

- Adding more/better support for logging out.
This commit is contained in:
Matt Gilman 2015-11-06 18:06:47 -05:00
parent d41b83c19b
commit d47c00f00e
12 changed files with 86 additions and 42 deletions

View File

@ -88,17 +88,16 @@ public class NiFiWebApiSecurityConfiguration extends WebSecurityConfigurerAdapte
.sessionManagement() .sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS); .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// verify that login authentication is enabled
if (loginIdentityProvider != null) { if (loginIdentityProvider != null) {
// login authentication for /token - exchanges for JWT for subsequent API usage
http.addFilterBefore(buildLoginFilter("/token"), UsernamePasswordAuthenticationFilter.class);
// verify the configured login authenticator supports user login registration // verify the configured login authenticator supports user login registration
if (loginIdentityProvider.supportsRegistration()) { if (loginIdentityProvider.supportsRegistration()) {
http.addFilterBefore(buildRegistrationFilter("/registration"), UsernamePasswordAuthenticationFilter.class); http.addFilterBefore(buildRegistrationFilter("/registration"), UsernamePasswordAuthenticationFilter.class);
} }
} }
// login authentication for /token - exchanges for JWT for subsequent API usage
http.addFilterBefore(buildLoginFilter("/token"), UsernamePasswordAuthenticationFilter.class);
// registration status - will check the status of a user's account registration (regardless if its based on login or not) // registration status - will check the status of a user's account registration (regardless if its based on login or not)
http.addFilterBefore(buildRegistrationStatusFilter("/registration/status"), UsernamePasswordAuthenticationFilter.class); http.addFilterBefore(buildRegistrationStatusFilter("/registration/status"), UsernamePasswordAuthenticationFilter.class);
@ -111,9 +110,11 @@ public class NiFiWebApiSecurityConfiguration extends WebSecurityConfigurerAdapte
// x509 // x509
http.addFilterAfter(buildX509Filter(), AnonymousAuthenticationFilter.class); http.addFilterAfter(buildX509Filter(), AnonymousAuthenticationFilter.class);
// jwt // jwt - consider when configured for log in
if (loginIdentityProvider != null) {
http.addFilterAfter(buildJwtFilter(), AnonymousAuthenticationFilter.class); http.addFilterAfter(buildJwtFilter(), AnonymousAuthenticationFilter.class);
} }
}
@Bean @Bean
@Override @Override

View File

@ -86,6 +86,11 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
// if there is no certificate, look for an existing token // if there is no certificate, look for an existing token
if (certificate == null) { if (certificate == null) {
// if not configured for login, don't consider existing tokens
if (loginIdentityProvider == null) {
throw new BadCredentialsException("Login not supported.");
}
final String principal = jwtService.getAuthentication(request); final String principal = jwtService.getAuthentication(request);
if (principal == null) { if (principal == null) {
@ -129,6 +134,11 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
return new LoginAuthenticationToken(preAuthenticatedCredentials); return new LoginAuthenticationToken(preAuthenticatedCredentials);
} }
} else { } else {
// if not configuration for login, don't consider credentials
if (loginIdentityProvider == null) {
throw new BadCredentialsException("Login not supported.");
}
if (loginIdentityProvider.authenticate(credentials)) { if (loginIdentityProvider.authenticate(credentials)) {
return new LoginAuthenticationToken(credentials); return new LoginAuthenticationToken(credentials);
} else { } else {

View File

@ -120,11 +120,6 @@ public class RegistrationFilter extends AbstractAuthenticationProcessingFilter {
// generate JWT for response // generate JWT for response
jwtService.addToken(response, authentication); jwtService.addToken(response, authentication);
// mark as successful
response.setStatus(HttpServletResponse.SC_CREATED);
response.setContentType("text/plain");
response.setContentLength(0);
} }
@Override @Override

View File

@ -37,6 +37,9 @@
${nf.login.script.tags} ${nf.login.script.tags}
</head> </head>
<body class="login-body"> <body class="login-body">
<div id="user-logout-container" class="hidden">
<span id="user-logout" class="link">logout</span>
</div>
<div id="login-contents-container"> <div id="login-contents-container">
<jsp:include page="/WEB-INF/partials/login/login-message.jsp"/> <jsp:include page="/WEB-INF/partials/login/login-message.jsp"/>
<jsp:include page="/WEB-INF/partials/login/login-form.jsp"/> <jsp:include page="/WEB-INF/partials/login/login-form.jsp"/>

View File

@ -27,8 +27,8 @@
<body class="message-pane"> <body class="message-pane">
<div class="message-pane-message-box"> <div class="message-pane-message-box">
<p class="message-pane-title"><%= request.getAttribute("title") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getAttribute("title").toString()) %></p> <div class="message-pane-title"><%= request.getAttribute("title") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getAttribute("title").toString()) %></div>
<p class="message-pane-content"><%= request.getAttribute("messages") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getAttribute("messages").toString()) %></p> <div class="message-pane-content"><%= request.getAttribute("messages") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getAttribute("messages").toString()) %></div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -45,7 +45,7 @@
<div id="header-links-container"> <div id="header-links-container">
<ul> <ul>
<li id="current-user-container"> <li id="current-user-container">
<div id="anonymous-user-alert"></div> <div id="anonymous-user-alert" class="hidden"></div>
<div id="current-user"></div> <div id="current-user"></div>
<div class="clear"></div> <div class="clear"></div>
</li> </li>

View File

@ -22,8 +22,6 @@
<div class="setting-name">User</div> <div class="setting-name">User</div>
<div class="setting-field"> <div class="setting-field">
<div id="nifi-user-submit-justification"></div> <div id="nifi-user-submit-justification"></div>
<span id="nifi-user-submit-justification-logout" class="link hidden">logout</span>
<div class="clear"></div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -16,8 +16,11 @@
--%> --%>
<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %> <%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
<div id="message-pane" class="message-pane hidden"> <div id="message-pane" class="message-pane hidden">
<div id="user-logout-container" class="hidden">
<span id="user-logout" class="link">logout</span>
</div>
<div class="message-pane-message-box"> <div class="message-pane-message-box">
<p id="message-title" class="message-pane-title"></p> <div id="message-title" class="message-pane-title"></div>
<p id="message-content" class="message-pane-content"></p> <div id="message-content" class="message-pane-content"></div>
</div> </div>
</div> </div>

View File

@ -81,16 +81,9 @@ body.login-body input, body.login-body textarea {
} }
#nifi-user-submit-justification { #nifi-user-submit-justification {
float: left;
font-weight: bold; font-weight: bold;
} }
#nifi-user-submit-justification-logout {
margin-left: 10px;
float: left;
text-decoration: underline;
}
#nifi-registration-justification { #nifi-registration-justification {
height: 200px; height: 200px;
} }

View File

@ -77,6 +77,17 @@ div.context-menu-provenance {
background-position: top left; background-position: top left;
} }
#user-logout-container {
position: absolute;
left: 478px;
top: 100px;
z-index: 1300;
}
#user-logout {
text-decoration: underline;
}
/* /*
General Styles General Styles
*/ */

View File

@ -23,7 +23,7 @@ $(document).ready(function () {
nf.Login = (function () { nf.Login = (function () {
var isAnonymous = false; var supportsAnonymous = false;
var config = { var config = {
urls: { urls: {
@ -165,9 +165,14 @@ nf.Login = (function () {
'password': password, 'password': password,
'justification': $('#nifi-registration-justification').val() 'justification': $('#nifi-registration-justification').val()
} }
}).done(function (response, status, xhr) { }).done(function (jwt) {
// store the jwt
nf.Storage.setItem('jwt', jwt);
showLogoutLink();
// inform the user of their pending request
var markup = 'An administrator will process your request shortly.'; var markup = 'An administrator will process your request shortly.';
if (isAnonymous === true) { if (supportsAnonymous === true) {
markup += '<br/><br/>In the meantime you can continue accessing anonymously.'; markup += '<br/><br/>In the meantime you can continue accessing anonymously.';
} }
@ -195,7 +200,7 @@ nf.Login = (function () {
} }
}).done(function (response) { }).done(function (response) {
var markup = 'An administrator will process your request shortly.'; var markup = 'An administrator will process your request shortly.';
if (isAnonymous === true) { if (supportsAnonymous === true) {
markup += '<br/><br/>In the meantime you can continue accessing anonymously.'; markup += '<br/><br/>In the meantime you can continue accessing anonymously.';
} }
@ -239,6 +244,20 @@ nf.Login = (function () {
return ''; return '';
}; };
var logout = function () {
nf.Storage.removeItem('jwt');
};
var showLogoutLink = function () {
$('#user-logout-container').show();
// handle logout
$('#user-logout').on('click', function () {
logout();
window.location = '/nifi/login';
});
};
return { return {
/** /**
* Initializes the login page. * Initializes the login page.
@ -250,15 +269,9 @@ nf.Login = (function () {
var needsLogin = false; var needsLogin = false;
var needsNiFiRegistration = false; var needsNiFiRegistration = false;
var logout = function () { if (nf.Storage.getItem('jwt') !== null) {
nf.Storage.removeItem('jwt'); showLogoutLink();
}; }
// handle logout
$('#nifi-user-submit-justification-logout').on('click', function () {
logout();
window.location = '/nifi/login';
});
var token = $.ajax({ var token = $.ajax({
type: 'GET', type: 'GET',
@ -276,7 +289,7 @@ nf.Login = (function () {
identity.done(function (response) { identity.done(function (response) {
// if the user is anonymous see if they need to login or if they are working with a certificate // if the user is anonymous see if they need to login or if they are working with a certificate
if (response.identity === 'anonymous') { if (response.identity === 'anonymous') {
isAnonymous = true; supportsAnonymous = true;
// request a token without including credentials, if successful then the user is using a certificate // request a token without including credentials, if successful then the user is using a certificate
token.done(function (jwt) { token.done(function (jwt) {

View File

@ -63,6 +63,23 @@ $(document).ready(function () {
// initialize the tooltips // initialize the tooltips
$('img.setting-icon').qtip(nf.Common.config.tooltipConfig); $('img.setting-icon').qtip(nf.Common.config.tooltipConfig);
// shows the logout link in the message-pane when appropriate
if (nf.Storage.getItem('jwt')) {
$('#user-logout-container').show();
}
// handle logout
$('#user-logout').on('click', function () {
nf.Storage.removeItem('jwt');
// reload as appropriate
if (top !== window) {
parent.window.location = '/nifi';
} else {
window.location = '/nifi';
}
});
}); });
// Define a common utility class used across the entire application. // Define a common utility class used across the entire application.