begin tidy up of error handling for authentication.
This commit is contained in:
@@ -47,7 +47,7 @@ public class ApiGlobalErrorResponse {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("401");
|
||||
globalErrorResponse.setDeveloperMessage("No authentication details were passed in api request.");
|
||||
globalErrorResponse.setDeveloperMessage("Invalid authentication details were passed in api request.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authenticated");
|
||||
globalErrorResponse.setDefaultUserMessage("Unauthenticated. Please login.");
|
||||
|
||||
+30
-19
@@ -9,7 +9,9 @@ import org.mifosng.data.AuthenticatedUserData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
@@ -17,6 +19,7 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
@@ -43,28 +46,36 @@ public class ApiDelegatingAuthenticationProvider extends AbstractUserDetailsAuth
|
||||
@Override
|
||||
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
|
||||
|
||||
String password = (String) authentication.getCredentials();
|
||||
|
||||
String platformApiUrl = this.applicationConfigurationService.retrievePlatformApiUrl();
|
||||
String authUrlExtension = "authentication?username=" + username + "&password=" + password;
|
||||
StringBuilder authenticationApiUrl = new StringBuilder(platformApiUrl).append(authUrlExtension);
|
||||
|
||||
URI restUri = URI.create(authenticationApiUrl.toString());
|
||||
ResponseEntity<AuthenticatedUserData> s = this.restTemplate.postForEntity(restUri, authRequest(), AuthenticatedUserData.class);
|
||||
|
||||
UserDetails userDetails = null;
|
||||
AuthenticatedUserData authenticatedUserData = s.getBody();
|
||||
if (authenticatedUserData.isAuthenticated()) {
|
||||
try {
|
||||
String password = (String) authentication.getCredentials();
|
||||
|
||||
Collection<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
|
||||
for (String permission : authenticatedUserData.getPermissions()) {
|
||||
authorities.add(new SimpleGrantedAuthority(permission));
|
||||
String platformApiUrl = this.applicationConfigurationService.retrievePlatformApiUrl();
|
||||
String authUrlExtension = "authentication?username=" + username + "&password=" + password;
|
||||
StringBuilder authenticationApiUrl = new StringBuilder(platformApiUrl).append(authUrlExtension);
|
||||
|
||||
URI restUri = URI.create(authenticationApiUrl.toString());
|
||||
ResponseEntity<AuthenticatedUserData> s = this.restTemplate.postForEntity(restUri, authRequest(), AuthenticatedUserData.class);
|
||||
|
||||
UserDetails userDetails = null;
|
||||
AuthenticatedUserData authenticatedUserData = s.getBody();
|
||||
if (authenticatedUserData.isAuthenticated()) {
|
||||
|
||||
Collection<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
|
||||
for (String permission : authenticatedUserData.getPermissions()) {
|
||||
authorities.add(new SimpleGrantedAuthority(permission));
|
||||
}
|
||||
User user = new User(authenticatedUserData.getUsername(), "[not needed]", authorities);
|
||||
userDetails = new BasicAuthUserDetails(user, authenticatedUserData.getBase64EncodedAuthenticationKey(), platformApiUrl);
|
||||
}
|
||||
User user = new User(authenticatedUserData.getUsername(), "[not needed]", authorities);
|
||||
userDetails = new BasicAuthUserDetails(user, authenticatedUserData.getBase64EncodedAuthenticationKey(), platformApiUrl);
|
||||
|
||||
return userDetails;
|
||||
} catch (HttpClientErrorException clientErrorException) {
|
||||
if (clientErrorException.getStatusCode().equals(HttpStatus.UNAUTHORIZED)) {
|
||||
throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
|
||||
}
|
||||
|
||||
throw clientErrorException;
|
||||
}
|
||||
|
||||
return userDetails;
|
||||
}
|
||||
|
||||
private HttpEntity<Object> authRequest() {
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
|
||||
|
||||
<http security="none" pattern="/login" />
|
||||
<http security="none" pattern="/logout" />
|
||||
|
||||
<http use-expressions="true" pattern="/**" create-session="always">
|
||||
<intercept-url pattern="/**" access="isFullyAuthenticated()" />
|
||||
|
||||
<!-- login-page="/login" -->
|
||||
<form-login />
|
||||
<logout invalidate-session="true" logout-url="/signout" logout-success-url="/logout" />
|
||||
</http>
|
||||
|
||||
@@ -50,8 +50,8 @@
|
||||
|
||||
<mvc:resources location="/WEB-INF/static/" mapping="/resources/**" cache-period="31556926"/>
|
||||
|
||||
<mvc:view-controller path="/login" view-name="login"/>
|
||||
<mvc:view-controller path="/logout" view-name="logout"/>
|
||||
<mvc:view-controller path="/oauth_error" view-name="oauth_error"/>
|
||||
|
||||
<!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
|
||||
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
<%@ page session="true" %>
|
||||
<%@ page import="org.springframework.security.core.AuthenticationException" %>
|
||||
<%@ page import="org.springframework.security.web.WebAttributes" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
|
||||
<c:set var="applicationName" scope="session" value="Mifos - Individual Lending: " />
|
||||
<c:set var="pageTitle" scope="session" value="Login"/>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<jsp:include page="common-head.jsp" />
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#login').button();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
<div id="content">
|
||||
<div id="spacer" style="line-height: 25px;"> </div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
<!--
|
||||
<h1>Mifos - Individual Lending: Login</h1>
|
||||
<div id="formcontainer">
|
||||
|
||||
<c:if test="${!empty sessionScope.SPRING_SECURITY_LAST_EXCEPTION}">
|
||||
<div class="ui-widget">
|
||||
<div class="ui-state-error ui-corner-all">
|
||||
<span class="ui-icon ui-icon-alert" style="float: left; margin-right: 5px;" ></span>
|
||||
<span>You have the following errors:</span>
|
||||
<div style="margin-left: 5px;">
|
||||
<p>Your login attempt was not successful. (<%= ((AuthenticationException) session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION)).getMessage() %>)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:remove scope="session" var="SPRING_SECURITY_LAST_EXCEPTION"/>
|
||||
|
||||
<c:url value="/j_spring_security_check" var="loginFilterUrl" />
|
||||
<c:url value="${successUrl}" var="authSuccessUrl" />
|
||||
|
||||
<form method="post" action="${loginFilterUrl}">
|
||||
<fieldset>
|
||||
<legend>Login</legend>
|
||||
<label for="username">Username:</label>
|
||||
<input type="hidden" name="successUrl" value="${successUrl}" />
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${param.oauth_token == null}">
|
||||
<input id="testone" type="hidden" name="oauth_token" value="${requestScope.oauth_token}" />
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<input id="testtwo" type="hidden" name="oauth_token" value="${param.oauth_token}" />
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
|
||||
<input size="75" type="text" name="j_username" id="username" title="Username for authentication." />
|
||||
<label for="password">Password:</label>
|
||||
<input size="75" type="password" name="j_password" id="password" title="Password for authentication."/>
|
||||
<div id="formbuttons">
|
||||
<button type="submit" id="login" name="login" title="Log in to application.">Login</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
-->
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package org.mifosng.platform.api.errorhandling;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import org.mifosng.data.ApiGlobalErrorResponse;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* An {@link ExceptionMapper} to map {@link BadCredentialsException} thrown by platform during authentication into a HTTP API friendly format.
|
||||
*
|
||||
* The {@link BadCredentialsException} is thrown by spring security on platform when an attempt is made to authenticate using invalid username/password credentials.
|
||||
*/
|
||||
@Provider
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class BadCredentialsExceptionMapper implements ExceptionMapper<BadCredentialsException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(BadCredentialsException exception) {
|
||||
return Response.status(Status.UNAUTHORIZED).entity(ApiGlobalErrorResponse.unAuthenticated()).build();
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package org.mifosng.platform.api.infrastructure;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("apiAuthenticationEntryPoint")
|
||||
public final class ApiAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
@Override
|
||||
public final void commence(HttpServletRequest request,
|
||||
HttpServletResponse response, AuthenticationException authException)
|
||||
throws IOException {
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthenticated");
|
||||
}
|
||||
}
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
package org.mifosng.platform.api.infrastructure;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class ApiAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
|
||||
|
||||
private RequestCache requestCache = new HttpSessionRequestCache();
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request,
|
||||
HttpServletResponse response, Authentication authentication)
|
||||
throws ServletException, IOException {
|
||||
SavedRequest savedRequest = requestCache.getRequest(request, response);
|
||||
|
||||
if (savedRequest == null) {
|
||||
super.onAuthenticationSuccess(request, response, authentication);
|
||||
|
||||
return;
|
||||
}
|
||||
String targetUrlParameter = getTargetUrlParameter();
|
||||
if (isAlwaysUseDefaultTargetUrl()
|
||||
|| (targetUrlParameter != null && StringUtils.hasText(request
|
||||
.getParameter(targetUrlParameter)))) {
|
||||
requestCache.removeRequest(request, response);
|
||||
super.onAuthenticationSuccess(request, response, authentication);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
clearAuthenticationAttributes(request);
|
||||
|
||||
// // Use the DefaultSavedRequest URL
|
||||
// String targetUrl = savedRequest.getRedirectUrl();
|
||||
// logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl);
|
||||
// getRedirectStrategy().sendRedirect(request, response, targetUrl);
|
||||
}
|
||||
|
||||
public void setRequestCache(RequestCache requestCache) {
|
||||
this.requestCache = requestCache;
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,13 @@
|
||||
<div id="container">
|
||||
<div id="content">
|
||||
<div id="spacer" style="line-height: 25px;"> </div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
<!--
|
||||
<h1>Mifos - Individual Lending: Login</h1>
|
||||
<div id="formcontainer">
|
||||
|
||||
@@ -63,8 +70,4 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
-->
|
||||
Reference in New Issue
Block a user