[Minor] Don't log exceptions if user fails to auth
This commit is contained in:
parent
1102f34d18
commit
8e06ccb7e1
|
@ -31,4 +31,14 @@ public class AccessDeniedException extends PrivilegeException {
|
||||||
public AccessDeniedException(String msg) {
|
public AccessDeniedException(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param msg
|
||||||
|
* detail on why and where access was denied
|
||||||
|
* @param e
|
||||||
|
* root exception
|
||||||
|
*/
|
||||||
|
public AccessDeniedException(String msg, Exception e) {
|
||||||
|
super(msg, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,4 +16,14 @@ public class InvalidCredentialsException extends AccessDeniedException {
|
||||||
public InvalidCredentialsException(String msg) {
|
public InvalidCredentialsException(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param msg
|
||||||
|
* detail on why and where access was denied
|
||||||
|
* @param e
|
||||||
|
* root exception
|
||||||
|
*/
|
||||||
|
public InvalidCredentialsException(String msg, Exception e) {
|
||||||
|
super(msg, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1119,10 +1119,9 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
||||||
return certificate;
|
return certificate;
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
String msg = "User {0} Failed to authenticate: {1}"; //$NON-NLS-1$
|
String msg = "User {0} failed to authenticate: {1}"; //$NON-NLS-1$
|
||||||
msg = MessageFormat.format(msg, username, e.getMessage());
|
msg = MessageFormat.format(msg, username, e.getMessage());
|
||||||
logger.error(msg);
|
throw new InvalidCredentialsException(msg, e);
|
||||||
throw e;
|
|
||||||
} finally {
|
} finally {
|
||||||
clearPassword(password);
|
clearPassword(password);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package li.strolch.privilege.handler;
|
package li.strolch.privilege.handler;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -27,24 +26,7 @@ public abstract class UserChallengeHandler {
|
||||||
* a map containing configuration properties
|
* a map containing configuration properties
|
||||||
*/
|
*/
|
||||||
public void initialize(Map<String, String> parameterMap) {
|
public void initialize(Map<String, String> parameterMap) {
|
||||||
this.challenges = Collections.synchronizedMap(new HashMap<>());
|
this.challenges = new HashMap<>();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initiate a password reset challenge for the given user
|
|
||||||
*
|
|
||||||
* @param usage
|
|
||||||
* the {@link Usage} for this certificate
|
|
||||||
* @param user
|
|
||||||
* the user for which to initiate the challenge for
|
|
||||||
*/
|
|
||||||
public void initiateChallengeFor(Usage usage, User user) {
|
|
||||||
|
|
||||||
String challenge = generateChallenge();
|
|
||||||
UserChallenge userChallenge = new UserChallenge(usage, user, challenge);
|
|
||||||
this.challenges.put(user, userChallenge);
|
|
||||||
|
|
||||||
sendChallengeToUser(user, challenge);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,6 +39,23 @@ public abstract class UserChallengeHandler {
|
||||||
return challenge;
|
return challenge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiate a password reset challenge for the given user
|
||||||
|
*
|
||||||
|
* @param usage
|
||||||
|
* the {@link Usage} for this certificate
|
||||||
|
* @param user
|
||||||
|
* the user for which to initiate the challenge for
|
||||||
|
*/
|
||||||
|
public synchronized void initiateChallengeFor(Usage usage, User user) {
|
||||||
|
|
||||||
|
String challenge = generateChallenge();
|
||||||
|
UserChallenge userChallenge = new UserChallenge(usage, user, challenge);
|
||||||
|
this.challenges.put(user, userChallenge);
|
||||||
|
|
||||||
|
sendChallengeToUser(user, challenge);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the response of a challenge for the given username
|
* Validate the response of a challenge for the given username
|
||||||
*
|
*
|
||||||
|
@ -70,18 +69,25 @@ public abstract class UserChallengeHandler {
|
||||||
*
|
*
|
||||||
* @return the challenge
|
* @return the challenge
|
||||||
*/
|
*/
|
||||||
public UserChallenge validateResponse(User user, String challenge) throws PrivilegeException {
|
public synchronized UserChallenge validateResponse(User user, String challenge) throws PrivilegeException {
|
||||||
|
|
||||||
UserChallenge userChallenge = this.challenges.remove(user);
|
// get the challenge
|
||||||
|
UserChallenge userChallenge = this.challenges.get(user);
|
||||||
if (userChallenge == null)
|
if (userChallenge == null)
|
||||||
throw new PrivilegeException("No challenge exists for user " + user.getUsername());
|
throw new PrivilegeException("No challenge exists for user " + user.getUsername());
|
||||||
|
|
||||||
|
// validate the challenge
|
||||||
if (!userChallenge.getUser().equals(user))
|
if (!userChallenge.getUser().equals(user))
|
||||||
throw new PrivilegeException("UserChallenge invalid: Wrong user!");
|
throw new PrivilegeException("UserChallenge invalid: Wrong user!");
|
||||||
|
|
||||||
if (!userChallenge.getChallenge().equals(challenge))
|
if (!userChallenge.getChallenge().equals(challenge))
|
||||||
throw new PrivilegeException("Challenge is invalid!");
|
throw new PrivilegeException("Challenge is invalid!");
|
||||||
|
|
||||||
|
// then remove it
|
||||||
|
this.challenges.remove(user);
|
||||||
|
|
||||||
|
// it's full filled
|
||||||
userChallenge.fulfilled();
|
userChallenge.fulfilled();
|
||||||
|
|
||||||
return userChallenge;
|
return userChallenge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ import li.strolch.rest.StrolchRestfulConstants;
|
||||||
import li.strolch.rest.StrolchSessionHandler;
|
import li.strolch.rest.StrolchSessionHandler;
|
||||||
import li.strolch.rest.model.Result;
|
import li.strolch.rest.model.Result;
|
||||||
import li.strolch.runtime.privilege.PrivilegeHandler;
|
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||||
|
import li.strolch.utils.helper.ExceptionHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
@ -168,11 +169,11 @@ public class AuthenticationService {
|
||||||
.header(HttpHeaders.AUTHORIZATION, certificate.getAuthToken()).cookie(cookie).build();
|
.header(HttpHeaders.AUTHORIZATION, certificate.getAuthToken()).cookie(cookie).build();
|
||||||
|
|
||||||
} catch (InvalidCredentialsException e) {
|
} catch (InvalidCredentialsException e) {
|
||||||
logger.error(e.getMessage(), e);
|
logger.error("Authentication failed due to: " + e.getMessage());
|
||||||
loginResult.addProperty("msg", "Could not log in as the given credentials are invalid"); //$NON-NLS-1$
|
loginResult.addProperty("msg", "Could not log in as the given credentials are invalid"); //$NON-NLS-1$
|
||||||
return Response.status(Status.UNAUTHORIZED).entity(loginResult.toString()).build();
|
return Response.status(Status.UNAUTHORIZED).entity(loginResult.toString()).build();
|
||||||
} catch (AccessDeniedException e) {
|
} catch (AccessDeniedException e) {
|
||||||
logger.error(e.getMessage(), e);
|
logger.error("Authentication failed due to: " + e.getMessage());
|
||||||
loginResult.addProperty("msg", MessageFormat.format("Could not log in due to: {0}", e.getMessage())); //$NON-NLS-1$
|
loginResult.addProperty("msg", MessageFormat.format("Could not log in due to: {0}", e.getMessage())); //$NON-NLS-1$
|
||||||
return Response.status(Status.UNAUTHORIZED).entity(loginResult.toString()).build();
|
return Response.status(Status.UNAUTHORIZED).entity(loginResult.toString()).build();
|
||||||
} catch (StrolchException | PrivilegeException e) {
|
} catch (StrolchException | PrivilegeException e) {
|
||||||
|
@ -208,7 +209,7 @@ public class AuthenticationService {
|
||||||
return Response.ok().entity(logoutResult.toString()).build();
|
return Response.ok().entity(logoutResult.toString()).build();
|
||||||
|
|
||||||
} catch (StrolchException | PrivilegeException e) {
|
} catch (StrolchException | PrivilegeException e) {
|
||||||
logger.error(e.getMessage(), e);
|
logger.error("Failed to invalidate session due to: " + e.getMessage());
|
||||||
logoutResult.addProperty("msg", MessageFormat.format("Could not logout due to: {0}", e.getMessage())); //$NON-NLS-1$
|
logoutResult.addProperty("msg", MessageFormat.format("Could not logout due to: {0}", e.getMessage())); //$NON-NLS-1$
|
||||||
return Response.status(Status.UNAUTHORIZED).entity(logoutResult.toString()).build();
|
return Response.status(Status.UNAUTHORIZED).entity(logoutResult.toString()).build();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -252,39 +253,61 @@ public class AuthenticationService {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Path("challenge")
|
@Path("challenge")
|
||||||
public Response initiateChallenge(String data) {
|
public Response initiateChallenge(String data) {
|
||||||
JsonObject jsonObject = new JsonParser().parse(data).getAsJsonObject();
|
|
||||||
String username = jsonObject.get("username").getAsString();
|
|
||||||
String usage = jsonObject.get("usage").getAsString();
|
|
||||||
|
|
||||||
StrolchSessionHandler sessionHandler = RestfulStrolchComponent.getInstance().getSessionHandler();
|
try {
|
||||||
sessionHandler.initiateChallengeFor(Usage.byValue(usage), username);
|
JsonObject jsonObject = new JsonParser().parse(data).getAsJsonObject();
|
||||||
|
String username = jsonObject.get("username").getAsString();
|
||||||
|
String usage = jsonObject.get("usage").getAsString();
|
||||||
|
|
||||||
return Response.ok(new Result(), MediaType.APPLICATION_JSON).build();
|
StrolchSessionHandler sessionHandler = RestfulStrolchComponent.getInstance().getSessionHandler();
|
||||||
|
sessionHandler.initiateChallengeFor(Usage.byValue(usage), username);
|
||||||
|
|
||||||
|
return Response.ok(new Result(), MediaType.APPLICATION_JSON).build();
|
||||||
|
|
||||||
|
} catch (PrivilegeException e) {
|
||||||
|
logger.error("Challenge initialization failed: " + e.getMessage());
|
||||||
|
JsonObject root = new JsonObject();
|
||||||
|
root.addProperty("msg", ExceptionHelper.getExceptionMessage(e));
|
||||||
|
String json = new Gson().toJson(root);
|
||||||
|
return Response.status(Status.UNAUTHORIZED).entity(json).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PUT
|
@PUT
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Path("challenge")
|
@Path("challenge")
|
||||||
public Response validateChallenge(@Context HttpServletRequest request, String data) {
|
public Response validateChallenge(@Context HttpServletRequest request, String data) {
|
||||||
JsonObject jsonObject = new JsonParser().parse(data).getAsJsonObject();
|
|
||||||
String username = jsonObject.get("username").getAsString();
|
|
||||||
String challenge = jsonObject.get("challenge").getAsString();
|
|
||||||
|
|
||||||
StrolchSessionHandler sessionHandler = RestfulStrolchComponent.getInstance().getSessionHandler();
|
try {
|
||||||
Certificate certificate = sessionHandler.validateChallenge(username, challenge);
|
|
||||||
|
|
||||||
jsonObject = new JsonObject();
|
JsonObject jsonObject = new JsonParser().parse(data).getAsJsonObject();
|
||||||
jsonObject.addProperty("authToken", certificate.getAuthToken());
|
String username = jsonObject.get("username").getAsString();
|
||||||
|
String challenge = jsonObject.get("challenge").getAsString();
|
||||||
|
|
||||||
boolean secureCookie = RestfulStrolchComponent.getInstance().isSecureCookie();
|
StrolchSessionHandler sessionHandler = RestfulStrolchComponent.getInstance().getSessionHandler();
|
||||||
if (secureCookie && !request.getScheme().equals("https")) {
|
Certificate certificate = sessionHandler.validateChallenge(username, challenge);
|
||||||
String msg = "Authorization cookie is secure, but connection is not secure! Cookie won't be passed to client!";
|
|
||||||
logger.warn(msg);
|
jsonObject = new JsonObject();
|
||||||
|
jsonObject.addProperty("authToken", certificate.getAuthToken());
|
||||||
|
|
||||||
|
boolean secureCookie = RestfulStrolchComponent.getInstance().isSecureCookie();
|
||||||
|
if (secureCookie && !request.getScheme().equals("https")) {
|
||||||
|
String msg = "Authorization cookie is secure, but connection is not secure! Cookie won't be passed to client!";
|
||||||
|
logger.warn(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
NewCookie cookie = new NewCookie(StrolchRestfulConstants.STROLCH_AUTHORIZATION, certificate.getAuthToken(),
|
||||||
|
"/", null, "Authorization header", (int) TimeUnit.DAYS.toSeconds(1), secureCookie);
|
||||||
|
|
||||||
|
return Response.ok().entity(jsonObject.toString())//
|
||||||
|
.header(HttpHeaders.AUTHORIZATION, certificate.getAuthToken()).cookie(cookie).build();
|
||||||
|
|
||||||
|
} catch (PrivilegeException e) {
|
||||||
|
logger.error("Challenge validation failed: " + e.getMessage());
|
||||||
|
JsonObject root = new JsonObject();
|
||||||
|
root.addProperty("msg", ExceptionHelper.getExceptionMessage(e));
|
||||||
|
String json = new Gson().toJson(root);
|
||||||
|
return Response.status(Status.UNAUTHORIZED).entity(json).build();
|
||||||
}
|
}
|
||||||
NewCookie cookie = new NewCookie(StrolchRestfulConstants.STROLCH_AUTHORIZATION, certificate.getAuthToken(), "/",
|
|
||||||
null, "Authorization header", (int) TimeUnit.DAYS.toSeconds(1), secureCookie);
|
|
||||||
|
|
||||||
return Response.ok().entity(jsonObject.toString())//
|
|
||||||
.header(HttpHeaders.AUTHORIZATION, certificate.getAuthToken()).cookie(cookie).build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue