mirror of https://github.com/apache/nifi.git
NIFI-655:
- Updating the login API authenticate method to use a richer set of exceptions. - UI code clean.
This commit is contained in:
parent
2e158d15be
commit
e61ccea7a0
|
@ -17,6 +17,7 @@
|
|||
package org.apache.nifi.authentication;
|
||||
|
||||
import org.apache.nifi.authentication.exception.IdentityAccessException;
|
||||
import org.apache.nifi.authentication.exception.InvalidLoginCredentialsException;
|
||||
import org.apache.nifi.authorization.exception.ProviderCreationException;
|
||||
import org.apache.nifi.authorization.exception.ProviderDestructionException;
|
||||
|
||||
|
@ -29,10 +30,10 @@ public interface LoginIdentityProvider {
|
|||
* Authenticates the specified login credentials.
|
||||
*
|
||||
* @param credentials the credentials
|
||||
* @return was able to check the user credentials and returns whether the user was authenticated
|
||||
* @throws InvalidLoginCredentialsException The login credentials were invalid
|
||||
* @throws IdentityAccessException Unable to register the user due to an issue accessing the underlying storage
|
||||
*/
|
||||
boolean authenticate(LoginCredentials credentials) throws IdentityAccessException;
|
||||
void authenticate(LoginCredentials credentials) throws InvalidLoginCredentialsException, IdentityAccessException;
|
||||
|
||||
/**
|
||||
* Called immediately after instance creation for implementers to perform additional setup
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.authentication.exception;
|
||||
|
||||
/**
|
||||
* Represents the case when the identity could not be confirmed because the
|
||||
* login credentials were invalid.
|
||||
*/
|
||||
public class InvalidLoginCredentialsException extends RuntimeException {
|
||||
|
||||
public InvalidLoginCredentialsException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public InvalidLoginCredentialsException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.apache.nifi.authentication.LoginCredentials;
|
||||
import org.apache.nifi.authentication.LoginIdentityProvider;
|
||||
import org.apache.nifi.authentication.exception.IdentityAccessException;
|
||||
import org.apache.nifi.authentication.exception.InvalidLoginCredentialsException;
|
||||
import org.apache.nifi.util.StringUtils;
|
||||
import org.apache.nifi.web.security.ProxiedEntitiesUtils;
|
||||
import org.apache.nifi.web.security.jwt.JwtService;
|
||||
|
@ -142,11 +143,13 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
|
|||
}
|
||||
|
||||
try {
|
||||
if (loginIdentityProvider.authenticate(credentials)) {
|
||||
return new LoginAuthenticationToken(credentials);
|
||||
} else {
|
||||
throw new BadCredentialsException("The supplied username and password are not valid.");
|
||||
}
|
||||
// attempt to authenticate
|
||||
loginIdentityProvider.authenticate(credentials);
|
||||
|
||||
// create the authentication token
|
||||
return new LoginAuthenticationToken(credentials);
|
||||
} catch (final InvalidLoginCredentialsException ilce) {
|
||||
throw new BadCredentialsException("The supplied username and password are not valid.", ilce);
|
||||
} catch (final IdentityAccessException iae) {
|
||||
throw new AuthenticationServiceException(iae.getMessage(), iae);
|
||||
}
|
||||
|
@ -195,11 +198,6 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
|
|||
|
||||
@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());
|
||||
|
||||
if (failed instanceof BadCredentialsException || failed instanceof AuthenticationCredentialsNotFoundException) {
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
} else if (failed instanceof AuthenticationServiceException) {
|
||||
|
@ -207,6 +205,11 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
|
|||
} else {
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
response.setContentType("text/plain");
|
||||
|
||||
final PrintWriter out = response.getWriter();
|
||||
out.println(failed.getMessage());
|
||||
}
|
||||
|
||||
public void setJwtService(JwtService jwtService) {
|
||||
|
|
|
@ -259,9 +259,9 @@ public class LoginIdentityProviderFactoryBean implements FactoryBean, Disposable
|
|||
return new LoginIdentityProvider() {
|
||||
|
||||
@Override
|
||||
public boolean authenticate(LoginCredentials credentials) {
|
||||
public void authenticate(LoginCredentials credentials) {
|
||||
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
|
||||
return baseProvider.authenticate(credentials);
|
||||
baseProvider.authenticate(credentials);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -141,16 +141,22 @@ nf.CanvasHeader = (function () {
|
|||
nf.Shell.showPage(config.urls.helpDocument);
|
||||
});
|
||||
|
||||
// hide the login link if the user is already logged in
|
||||
if ($('#current-user').text() !== nf.Canvas.ANONYMOUS_USER_TEXT) {
|
||||
// show the login link if supported and user is currently anonymous
|
||||
var isAnonymous = $('#current-user').text() === nf.Canvas.ANONYMOUS_USER_TEXT;
|
||||
if (supportsLogin === true && isAnonymous) {
|
||||
// login link
|
||||
$('#login-link').click(function () {
|
||||
nf.Shell.showPage('login', false);
|
||||
});
|
||||
} else {
|
||||
$('#login-link-container').css('display', 'none');
|
||||
}
|
||||
|
||||
// login link
|
||||
$('#login-link').click(function () {
|
||||
nf.Shell.showPage('login', false);
|
||||
});
|
||||
|
||||
|
||||
// if login is not supported, don't show the current user
|
||||
if (supportsLogin === false) {
|
||||
$('#current-user-container').css('display', 'none');
|
||||
}
|
||||
|
||||
// logout link
|
||||
$('#logout-link').click(function () {
|
||||
nf.Storage.removeItem("jwt");
|
||||
|
@ -172,11 +178,11 @@ nf.CanvasHeader = (function () {
|
|||
handler: {
|
||||
click: function () {
|
||||
var selection = nf.CanvasUtils.getSelection();
|
||||
|
||||
|
||||
// color the selected components
|
||||
selection.each(function (d) {
|
||||
var selected = d3.select(this);
|
||||
|
||||
|
||||
var revision = nf.Client.getRevision();
|
||||
var selectedData = selected.datum();
|
||||
|
||||
|
@ -215,7 +221,7 @@ nf.CanvasHeader = (function () {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// close the dialog
|
||||
$('#fill-color-dialog').modal('hide');
|
||||
}
|
||||
|
@ -256,20 +262,20 @@ nf.CanvasHeader = (function () {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// updates the color if its a valid hex color string
|
||||
var updateColor = function () {
|
||||
var hex = $('#fill-color-value').val();
|
||||
|
||||
|
||||
// only update the fill color when its a valid hex color string
|
||||
// #[six hex characters|three hex characters] case insensitive
|
||||
if (/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex)) {
|
||||
$('#fill-color').minicolors('value', hex);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// apply fill color from field on blur and enter press
|
||||
$('#fill-color-value').on('blur', updateColor).on('keyup', function(e) {
|
||||
$('#fill-color-value').on('blur', updateColor).on('keyup', function (e) {
|
||||
var code = e.keyCode ? e.keyCode : e.which;
|
||||
if (code === $.ui.keyCode.ENTER) {
|
||||
updateColor();
|
||||
|
@ -328,23 +334,22 @@ nf.CanvasHeader = (function () {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var toolbar = $('#toolbar');
|
||||
var groupButton = $('#action-group');
|
||||
$(window).on('resize', function() {
|
||||
$(window).on('resize', function () {
|
||||
if (toolbar.width() < MIN_TOOLBAR_WIDTH && groupButton.is(':visible')) {
|
||||
toolbar.find('.secondary').hide();
|
||||
} else if (toolbar.width() > MIN_TOOLBAR_WIDTH && groupButton.is(':hidden')) {
|
||||
toolbar.find('.secondary').show();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// set up the initial visibility
|
||||
if (toolbar.width() < MIN_TOOLBAR_WIDTH) {
|
||||
toolbar.find('.secondary').hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Reloads and clears any warnings.
|
||||
*/
|
||||
|
@ -359,7 +364,7 @@ nf.CanvasHeader = (function () {
|
|||
// hide the refresh link on the canvas
|
||||
$('#stats-last-refreshed').removeClass('alert');
|
||||
$('#refresh-required-container').hide();
|
||||
|
||||
|
||||
// hide the refresh link on the settings
|
||||
$('#settings-last-refreshed').removeClass('alert');
|
||||
$('#settings-refresh-required-icon').hide();
|
||||
|
|
|
@ -1087,6 +1087,13 @@ nf.Canvas = (function () {
|
|||
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) {
|
||||
$.ajax({
|
||||
|
@ -1106,8 +1113,9 @@ nf.Canvas = (function () {
|
|||
}).promise();
|
||||
|
||||
// ensure the config requests are loaded
|
||||
$.when(configXhr, userXhr).done(function (configResult) {
|
||||
$.when(configXhr, loginXhr, userXhr).done(function (configResult, loginResult) {
|
||||
var configResponse = configResult[0];
|
||||
var loginResponse = loginResult[0];
|
||||
|
||||
// calculate the canvas offset
|
||||
var canvasContainer = $('#canvas-container');
|
||||
|
@ -1115,6 +1123,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 () {
|
||||
|
@ -1134,7 +1143,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();
|
||||
|
|
|
@ -40,17 +40,18 @@ nf.Login = (function () {
|
|||
$('#login-message-container').show();
|
||||
};
|
||||
|
||||
var initializeLogin = function () {
|
||||
};
|
||||
|
||||
var showLogin = function () {
|
||||
$('#login-container').show();
|
||||
$('#user-registration-container').hide();
|
||||
$('#nifi-registration-container').hide();
|
||||
// reset the forms
|
||||
$('#username').val('');
|
||||
$('#password').val('');
|
||||
$('#login-submission-button').text('Log in');
|
||||
};
|
||||
|
||||
var initializeUserRegistration = function () {
|
||||
|
||||
// update the form visibility
|
||||
$('#login-container').show();
|
||||
$('#nifi-registration-container').hide();
|
||||
|
||||
// set the focus
|
||||
$('#username').focus();
|
||||
};
|
||||
|
||||
var initializeNiFiRegistration = function () {
|
||||
|
@ -64,26 +65,20 @@ nf.Login = (function () {
|
|||
});
|
||||
};
|
||||
|
||||
var showUserRegistration = function () {
|
||||
showNiFiRegistration();
|
||||
|
||||
$('div.nifi-submit-justification').hide();
|
||||
$('#user-registration-container').show();
|
||||
$('#login-submission-button').text('Create');
|
||||
};
|
||||
|
||||
var showNiFiRegistration = function () {
|
||||
// reset the forms
|
||||
$('#login-submission-button').text('Submit');
|
||||
$('#nifi-registration-justification').val('');
|
||||
|
||||
// update the form visibility
|
||||
$('#login-container').hide();
|
||||
$('#nifi-registration-container').show();
|
||||
$('#login-submission-button').text('Submit');
|
||||
};
|
||||
|
||||
var initializeSubmission = function () {
|
||||
$('#login-submission-button').on('click', function () {
|
||||
if ($('#login-container').is(':visible')) {
|
||||
login();
|
||||
} else if ($('#user-registration-container').is(':visible')) {
|
||||
createUserAccount();
|
||||
} else if ($('#nifi-registration-container').is(':visible')) {
|
||||
submitJustification();
|
||||
}
|
||||
|
@ -104,13 +99,51 @@ nf.Login = (function () {
|
|||
}).done(function (jwt) {
|
||||
// store the jwt and reload the page
|
||||
nf.Storage.setItem('jwt', jwt);
|
||||
|
||||
// check to see if they actually have access now
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: config.urls.identity,
|
||||
dataType: 'json'
|
||||
}).done(function (response) {
|
||||
if (response.identity === 'anonymous') {
|
||||
showLogoutLink();
|
||||
|
||||
// reload as appropriate
|
||||
if (top !== window) {
|
||||
parent.window.location = '/nifi';
|
||||
} else {
|
||||
window.location = '/nifi';
|
||||
}
|
||||
// show the user
|
||||
var user = getJwtSubject(jwt);
|
||||
$('#nifi-user-submit-justification').text(user);
|
||||
|
||||
// show the registration form
|
||||
initializeNiFiRegistration();
|
||||
showNiFiRegistration();
|
||||
} else {
|
||||
// reload as appropriate
|
||||
if (top !== window) {
|
||||
parent.window.location = '/nifi';
|
||||
} else {
|
||||
window.location = '/nifi';
|
||||
}
|
||||
}
|
||||
}).fail(function (xhr, status, error) {
|
||||
showLogoutLink();
|
||||
|
||||
// show the user
|
||||
var user = getJwtSubject(jwt);
|
||||
$('#nifi-user-submit-justification').text(user);
|
||||
|
||||
if (xhr.status === 401) {
|
||||
initializeNiFiRegistration();
|
||||
showNiFiRegistration();
|
||||
} 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();
|
||||
}
|
||||
});
|
||||
}).fail(function (xhr, status, error) {
|
||||
if (xhr.status === 400) {
|
||||
nf.Dialog.showOkDialog({
|
||||
|
@ -129,53 +162,6 @@ nf.Login = (function () {
|
|||
});
|
||||
};
|
||||
|
||||
var createUserAccount = function () {
|
||||
var password = $('#registration-password').val();
|
||||
var passwordConfirmation = $('#registration-password-confirmation').val();
|
||||
|
||||
// ensure the password matches
|
||||
if (password !== passwordConfirmation) {
|
||||
nf.Dialog.showOkDialog({
|
||||
dialogContent: 'The specified passwords do not match.',
|
||||
overlayBackground: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// attempt to create the user account registration
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: config.urls.registration,
|
||||
data: {
|
||||
'username': $('#registration-username').val(),
|
||||
'password': password,
|
||||
'justification': $('#nifi-registration-justification').val()
|
||||
}
|
||||
}).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.';
|
||||
if (supportsAnonymous === 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({
|
||||
|
@ -236,12 +222,6 @@ nf.Login = (function () {
|
|||
|
||||
var showLogoutLink = function () {
|
||||
$('#user-logout-container').show();
|
||||
|
||||
// handle logout
|
||||
$('#user-logout').on('click', function () {
|
||||
logout();
|
||||
window.location = '/nifi/login';
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
|
@ -297,11 +277,6 @@ nf.Login = (function () {
|
|||
// show the user
|
||||
$('#nifi-user-submit-justification').text(user);
|
||||
|
||||
// render the logout button if there is a token locally
|
||||
if (nf.Storage.getItem('jwt') !== null) {
|
||||
$('#nifi-user-submit-justification-logout').show();
|
||||
}
|
||||
|
||||
// anonymous user and 401 means they need nifi registration
|
||||
needsNiFiRegistration = true;
|
||||
} else {
|
||||
|
@ -346,11 +321,6 @@ nf.Login = (function () {
|
|||
// show the user
|
||||
$('#nifi-user-submit-justification').text(user);
|
||||
|
||||
// render the logout button if there is a token locally
|
||||
if (nf.Storage.getItem('jwt') !== null) {
|
||||
$('#nifi-user-submit-justification-logout').show();
|
||||
}
|
||||
|
||||
// 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 (tokenXhr) {
|
||||
|
@ -402,7 +372,6 @@ nf.Login = (function () {
|
|||
if (showMessage === true) {
|
||||
initializeMessage();
|
||||
} else if (needsLogin === true) {
|
||||
initializeLogin();
|
||||
showLogin();
|
||||
} else if (needsNiFiRegistration === true) {
|
||||
initializeNiFiRegistration();
|
||||
|
|
|
@ -72,13 +72,7 @@ $(document).ready(function () {
|
|||
// 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';
|
||||
}
|
||||
window.location = '/nifi/login';
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue