mirror of
https://github.com/apache/nifi.git
synced 2025-02-18 07:56:56 +00:00
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;
|
package org.apache.nifi.authentication;
|
||||||
|
|
||||||
import org.apache.nifi.authentication.exception.IdentityAccessException;
|
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.ProviderCreationException;
|
||||||
import org.apache.nifi.authorization.exception.ProviderDestructionException;
|
import org.apache.nifi.authorization.exception.ProviderDestructionException;
|
||||||
|
|
||||||
@ -29,10 +30,10 @@ public interface LoginIdentityProvider {
|
|||||||
* Authenticates the specified login credentials.
|
* Authenticates the specified login credentials.
|
||||||
*
|
*
|
||||||
* @param credentials the 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
|
* @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
|
* 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.LoginCredentials;
|
||||||
import org.apache.nifi.authentication.LoginIdentityProvider;
|
import org.apache.nifi.authentication.LoginIdentityProvider;
|
||||||
import org.apache.nifi.authentication.exception.IdentityAccessException;
|
import org.apache.nifi.authentication.exception.IdentityAccessException;
|
||||||
|
import org.apache.nifi.authentication.exception.InvalidLoginCredentialsException;
|
||||||
import org.apache.nifi.util.StringUtils;
|
import org.apache.nifi.util.StringUtils;
|
||||||
import org.apache.nifi.web.security.ProxiedEntitiesUtils;
|
import org.apache.nifi.web.security.ProxiedEntitiesUtils;
|
||||||
import org.apache.nifi.web.security.jwt.JwtService;
|
import org.apache.nifi.web.security.jwt.JwtService;
|
||||||
@ -142,11 +143,13 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (loginIdentityProvider.authenticate(credentials)) {
|
// attempt to authenticate
|
||||||
|
loginIdentityProvider.authenticate(credentials);
|
||||||
|
|
||||||
|
// create the authentication token
|
||||||
return new LoginAuthenticationToken(credentials);
|
return new LoginAuthenticationToken(credentials);
|
||||||
} else {
|
} catch (final InvalidLoginCredentialsException ilce) {
|
||||||
throw new BadCredentialsException("The supplied username and password are not valid.");
|
throw new BadCredentialsException("The supplied username and password are not valid.", ilce);
|
||||||
}
|
|
||||||
} catch (final IdentityAccessException iae) {
|
} catch (final IdentityAccessException iae) {
|
||||||
throw new AuthenticationServiceException(iae.getMessage(), iae);
|
throw new AuthenticationServiceException(iae.getMessage(), iae);
|
||||||
}
|
}
|
||||||
@ -195,11 +198,6 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void unsuccessfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException failed) throws IOException, ServletException {
|
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) {
|
if (failed instanceof BadCredentialsException || failed instanceof AuthenticationCredentialsNotFoundException) {
|
||||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
} else if (failed instanceof AuthenticationServiceException) {
|
} else if (failed instanceof AuthenticationServiceException) {
|
||||||
@ -207,6 +205,11 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
|
|||||||
} else {
|
} else {
|
||||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response.setContentType("text/plain");
|
||||||
|
|
||||||
|
final PrintWriter out = response.getWriter();
|
||||||
|
out.println(failed.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setJwtService(JwtService jwtService) {
|
public void setJwtService(JwtService jwtService) {
|
||||||
|
@ -259,9 +259,9 @@ public class LoginIdentityProviderFactoryBean implements FactoryBean, Disposable
|
|||||||
return new LoginIdentityProvider() {
|
return new LoginIdentityProvider() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean authenticate(LoginCredentials credentials) {
|
public void authenticate(LoginCredentials credentials) {
|
||||||
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
|
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
|
||||||
return baseProvider.authenticate(credentials);
|
baseProvider.authenticate(credentials);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,15 +141,21 @@ nf.CanvasHeader = (function () {
|
|||||||
nf.Shell.showPage(config.urls.helpDocument);
|
nf.Shell.showPage(config.urls.helpDocument);
|
||||||
});
|
});
|
||||||
|
|
||||||
// hide the login link if the user is already logged in
|
// show the login link if supported and user is currently anonymous
|
||||||
if ($('#current-user').text() !== nf.Canvas.ANONYMOUS_USER_TEXT) {
|
var isAnonymous = $('#current-user').text() === nf.Canvas.ANONYMOUS_USER_TEXT;
|
||||||
$('#login-link-container').css('display', 'none');
|
if (supportsLogin === true && isAnonymous) {
|
||||||
}
|
|
||||||
|
|
||||||
// login link
|
// login link
|
||||||
$('#login-link').click(function () {
|
$('#login-link').click(function () {
|
||||||
nf.Shell.showPage('login', false);
|
nf.Shell.showPage('login', false);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
$('#login-link-container').css('display', 'none');
|
||||||
|
}
|
||||||
|
|
||||||
|
// if login is not supported, don't show the current user
|
||||||
|
if (supportsLogin === false) {
|
||||||
|
$('#current-user-container').css('display', 'none');
|
||||||
|
}
|
||||||
|
|
||||||
// logout link
|
// logout link
|
||||||
$('#logout-link').click(function () {
|
$('#logout-link').click(function () {
|
||||||
@ -344,7 +350,6 @@ nf.CanvasHeader = (function () {
|
|||||||
toolbar.find('.secondary').hide();
|
toolbar.find('.secondary').hide();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reloads and clears any warnings.
|
* Reloads and clears any warnings.
|
||||||
*/
|
*/
|
||||||
|
@ -1087,6 +1087,13 @@ nf.Canvas = (function () {
|
|||||||
dataType: 'json'
|
dataType: 'json'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// get the login config
|
||||||
|
var loginXhr = $.ajax({
|
||||||
|
type: 'GET',
|
||||||
|
url: config.urls.loginConfig,
|
||||||
|
dataType: 'json'
|
||||||
|
});
|
||||||
|
|
||||||
// create the deferred cluster request
|
// create the deferred cluster request
|
||||||
var isClusteredRequest = $.Deferred(function (deferred) {
|
var isClusteredRequest = $.Deferred(function (deferred) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@ -1106,8 +1113,9 @@ nf.Canvas = (function () {
|
|||||||
}).promise();
|
}).promise();
|
||||||
|
|
||||||
// ensure the config requests are loaded
|
// 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 configResponse = configResult[0];
|
||||||
|
var loginResponse = loginResult[0];
|
||||||
|
|
||||||
// calculate the canvas offset
|
// calculate the canvas offset
|
||||||
var canvasContainer = $('#canvas-container');
|
var canvasContainer = $('#canvas-container');
|
||||||
@ -1115,6 +1123,7 @@ nf.Canvas = (function () {
|
|||||||
|
|
||||||
// get the config details
|
// get the config details
|
||||||
var configDetails = configResponse.config;
|
var configDetails = configResponse.config;
|
||||||
|
var loginDetails = loginResponse.config;
|
||||||
|
|
||||||
// when both request complete, load the application
|
// when both request complete, load the application
|
||||||
isClusteredRequest.done(function () {
|
isClusteredRequest.done(function () {
|
||||||
@ -1134,7 +1143,7 @@ nf.Canvas = (function () {
|
|||||||
nf.ContextMenu.init();
|
nf.ContextMenu.init();
|
||||||
nf.CanvasToolbar.init();
|
nf.CanvasToolbar.init();
|
||||||
nf.CanvasToolbox.init();
|
nf.CanvasToolbox.init();
|
||||||
nf.CanvasHeader.init();
|
nf.CanvasHeader.init(loginDetails.supportsLogin);
|
||||||
nf.GraphControl.init();
|
nf.GraphControl.init();
|
||||||
nf.Search.init();
|
nf.Search.init();
|
||||||
nf.Settings.init();
|
nf.Settings.init();
|
||||||
|
@ -40,17 +40,18 @@ nf.Login = (function () {
|
|||||||
$('#login-message-container').show();
|
$('#login-message-container').show();
|
||||||
};
|
};
|
||||||
|
|
||||||
var initializeLogin = function () {
|
|
||||||
};
|
|
||||||
|
|
||||||
var showLogin = function () {
|
var showLogin = function () {
|
||||||
$('#login-container').show();
|
// reset the forms
|
||||||
$('#user-registration-container').hide();
|
$('#username').val('');
|
||||||
$('#nifi-registration-container').hide();
|
$('#password').val('');
|
||||||
$('#login-submission-button').text('Log in');
|
$('#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 () {
|
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 () {
|
var showNiFiRegistration = function () {
|
||||||
|
// reset the forms
|
||||||
|
$('#login-submission-button').text('Submit');
|
||||||
|
$('#nifi-registration-justification').val('');
|
||||||
|
|
||||||
|
// update the form visibility
|
||||||
$('#login-container').hide();
|
$('#login-container').hide();
|
||||||
$('#nifi-registration-container').show();
|
$('#nifi-registration-container').show();
|
||||||
$('#login-submission-button').text('Submit');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var initializeSubmission = function () {
|
var initializeSubmission = function () {
|
||||||
$('#login-submission-button').on('click', function () {
|
$('#login-submission-button').on('click', function () {
|
||||||
if ($('#login-container').is(':visible')) {
|
if ($('#login-container').is(':visible')) {
|
||||||
login();
|
login();
|
||||||
} else if ($('#user-registration-container').is(':visible')) {
|
|
||||||
createUserAccount();
|
|
||||||
} else if ($('#nifi-registration-container').is(':visible')) {
|
} else if ($('#nifi-registration-container').is(':visible')) {
|
||||||
submitJustification();
|
submitJustification();
|
||||||
}
|
}
|
||||||
@ -105,12 +100,50 @@ nf.Login = (function () {
|
|||||||
// store the jwt and reload the page
|
// store the jwt and reload the page
|
||||||
nf.Storage.setItem('jwt', jwt);
|
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();
|
||||||
|
|
||||||
|
// show the user
|
||||||
|
var user = getJwtSubject(jwt);
|
||||||
|
$('#nifi-user-submit-justification').text(user);
|
||||||
|
|
||||||
|
// show the registration form
|
||||||
|
initializeNiFiRegistration();
|
||||||
|
showNiFiRegistration();
|
||||||
|
} else {
|
||||||
// reload as appropriate
|
// reload as appropriate
|
||||||
if (top !== window) {
|
if (top !== window) {
|
||||||
parent.window.location = '/nifi';
|
parent.window.location = '/nifi';
|
||||||
} else {
|
} else {
|
||||||
window.location = '/nifi';
|
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) {
|
}).fail(function (xhr, status, error) {
|
||||||
if (xhr.status === 400) {
|
if (xhr.status === 400) {
|
||||||
nf.Dialog.showOkDialog({
|
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 () {
|
var submitJustification = function () {
|
||||||
// attempt to create the nifi account registration
|
// attempt to create the nifi account registration
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@ -236,12 +222,6 @@ nf.Login = (function () {
|
|||||||
|
|
||||||
var showLogoutLink = function () {
|
var showLogoutLink = function () {
|
||||||
$('#user-logout-container').show();
|
$('#user-logout-container').show();
|
||||||
|
|
||||||
// handle logout
|
|
||||||
$('#user-logout').on('click', function () {
|
|
||||||
logout();
|
|
||||||
window.location = '/nifi/login';
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -297,11 +277,6 @@ nf.Login = (function () {
|
|||||||
// show the user
|
// show the user
|
||||||
$('#nifi-user-submit-justification').text(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
|
// anonymous user and 401 means they need nifi registration
|
||||||
needsNiFiRegistration = true;
|
needsNiFiRegistration = true;
|
||||||
} else {
|
} else {
|
||||||
@ -346,11 +321,6 @@ nf.Login = (function () {
|
|||||||
// show the user
|
// show the user
|
||||||
$('#nifi-user-submit-justification').text(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
|
// 401 from identity request and 200 from token means they have a certificate/token but have not yet requested an account
|
||||||
needsNiFiRegistration = true;
|
needsNiFiRegistration = true;
|
||||||
}).fail(function (tokenXhr) {
|
}).fail(function (tokenXhr) {
|
||||||
@ -402,7 +372,6 @@ nf.Login = (function () {
|
|||||||
if (showMessage === true) {
|
if (showMessage === true) {
|
||||||
initializeMessage();
|
initializeMessage();
|
||||||
} else if (needsLogin === true) {
|
} else if (needsLogin === true) {
|
||||||
initializeLogin();
|
|
||||||
showLogin();
|
showLogin();
|
||||||
} else if (needsNiFiRegistration === true) {
|
} else if (needsNiFiRegistration === true) {
|
||||||
initializeNiFiRegistration();
|
initializeNiFiRegistration();
|
||||||
|
@ -72,13 +72,7 @@ $(document).ready(function () {
|
|||||||
// handle logout
|
// handle logout
|
||||||
$('#user-logout').on('click', function () {
|
$('#user-logout').on('click', function () {
|
||||||
nf.Storage.removeItem('jwt');
|
nf.Storage.removeItem('jwt');
|
||||||
|
window.location = '/nifi/login';
|
||||||
// reload as appropriate
|
|
||||||
if (top !== window) {
|
|
||||||
parent.window.location = '/nifi';
|
|
||||||
} else {
|
|
||||||
window.location = '/nifi';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user