diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestAuthenticator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestAuthenticator.java index 4455118a435..fd132b441a1 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestAuthenticator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestAuthenticator.java @@ -73,132 +73,127 @@ public abstract class MidpointRestAuthenticator getAuthenticationEvaluator(); protected abstract T createAuthenticationContext(AuthorizationPolicy policy, ContainerRequestContext requestCtx); - public void handleRequest(AuthorizationPolicy policy, Message m, ContainerRequestContext requestCtx) { + public void handleRequest(AuthorizationPolicy policy, Message m, ContainerRequestContext requestCtx) { - if (policy == null){ - RestServiceUtil.createAbortMessage(requestCtx); - return; - } + if (policy == null) { + RestServiceUtil.createAbortMessage(requestCtx); + return; + } + T authenticationContext = createAuthenticationContext(policy, requestCtx); - T authenticationContext = createAuthenticationContext(policy, requestCtx); + if (authenticationContext == null) { + return; + } - if (authenticationContext == null) { - return; - } + String enteredUsername = authenticationContext.getUsername(); - String enteredUsername = authenticationContext.getUsername(); + if (enteredUsername == null) { + RestServiceUtil.createAbortMessage(requestCtx); + return; + } - if (enteredUsername == null){ - RestServiceUtil.createAbortMessage(requestCtx); - return; - } + LOGGER.trace("Authenticating username '{}' to REST service", enteredUsername); + + // We need to create task before attempting authentication. Task ID is also a session ID. + Task task = taskManager.createTaskInstance(ModelRestService.OPERATION_REST_SERVICE); + task.setChannel(SchemaConstants.CHANNEL_REST_URI); + + ConnectionEnvironment connEnv = ConnectionEnvironment.create(SchemaConstants.CHANNEL_REST_URI); + connEnv.setSessionIdOverride(task.getTaskIdentifier()); + UsernamePasswordAuthenticationToken token; + try { + token = getAuthenticationEvaluator().authenticate(connEnv, authenticationContext); + } catch (UsernameNotFoundException | BadCredentialsException | DisabledException | LockedException | + CredentialsExpiredException | AccessDeniedException | AuthenticationCredentialsNotFoundException | + AuthenticationServiceException e) { + LOGGER.trace("Exception while authenticating username '{}' to REST service: {}", enteredUsername, e.getMessage(), e); + requestCtx.abortWith(Response.status(Status.UNAUTHORIZED).build()); + return; + } - LOGGER.trace("Authenticating username '{}' to REST service", enteredUsername); + UserType user = ((MidPointPrincipal) token.getPrincipal()).getUser(); + task.setOwner(user.asPrismObject()); - // We need to create task before attempting authentication. Task ID is also a session ID. - Task task = taskManager.createTaskInstance(ModelRestService.OPERATION_REST_SERVICE); - task.setChannel(SchemaConstants.CHANNEL_REST_URI); + // m.put(RestServiceUtil.MESSAGE_PROPERTY_TASK_NAME, task); + if (!authorizeUser(user, null, enteredUsername, connEnv, requestCtx)) { + return; + } - ConnectionEnvironment connEnv = ConnectionEnvironment.create(SchemaConstants.CHANNEL_REST_URI); - connEnv.setSessionIdOverride(task.getTaskIdentifier()); - UsernamePasswordAuthenticationToken token; - try { - token = getAuthenticationEvaluator().authenticate(connEnv, authenticationContext); - } catch (UsernameNotFoundException | BadCredentialsException e) { - LOGGER.trace("Exception while authenticating username '{}' to REST service: {}", enteredUsername, e.getMessage(), e); - requestCtx.abortWith(Response.status(Status.UNAUTHORIZED).header("WWW-Authenticate", "Basic authentication failed. Cannot authenticate user.").build()); - return; - } catch (DisabledException | LockedException | CredentialsExpiredException | AccessDeniedException - | AuthenticationCredentialsNotFoundException | AuthenticationServiceException e) { - LOGGER.trace("Exception while authenticating username '{}' to REST service: {}", enteredUsername, e.getMessage(), e); - requestCtx.abortWith(Response.status(Status.FORBIDDEN).build()); - return; - } - - UserType user = ((MidPointPrincipal)token.getPrincipal()).getUser(); - task.setOwner(user.asPrismObject()); - - // m.put(RestServiceUtil.MESSAGE_PROPERTY_TASK_NAME, task); - if (!authorizeUser(user, null, enteredUsername, connEnv, requestCtx)){ - return; - } - - String oid = requestCtx.getHeaderString("Switch-To-Principal"); - OperationResult result = task.getResult(); - if (StringUtils.isNotBlank(oid)){ - try { - PrismObject authorizedUser = model.getObject(UserType.class, oid, null, task, result); - task.setOwner(authorizedUser); - if (!authorizeUser(AuthorizationConstants.AUTZ_REST_PROXY_URL, user, authorizedUser, enteredUsername, connEnv, requestCtx)){ - return; - } - authenticateUser(authorizedUser, authorizedUser.getName().getOrig(), connEnv, requestCtx); -// if (!authorizeUser(authorizedUser.asObjectable(), null, authorizedUser.getName().getOrig(), connEnv, requestCtx)){ -// return; -// } - } catch (ObjectNotFoundException | SchemaException | SecurityViolationException - | CommunicationException | ConfigurationException | ExpressionEvaluationException e) { - LOGGER.trace("Exception while authenticating user identified with '{}' to REST service: {}", oid, e.getMessage(), e); - requestCtx.abortWith(Response.status(Status.UNAUTHORIZED).header("WWW-Authenticate", "Proxy Authentication failed. Cannot authenticate user.").build()); + String oid = requestCtx.getHeaderString("Switch-To-Principal"); + OperationResult result = task.getResult(); + if (StringUtils.isNotBlank(oid)) { + try { + PrismObject authorizedUser = model.getObject(UserType.class, oid, null, task, result); + task.setOwner(authorizedUser); + if (!authorizeUser(AuthorizationConstants.AUTZ_REST_PROXY_URL, user, authorizedUser, enteredUsername, connEnv, requestCtx)) { return; } - - - } - - m.put(RestServiceUtil.MESSAGE_PROPERTY_TASK_NAME, task); - - LOGGER.trace("Authorized to use REST service ({})", user); + authenticateUser(authorizedUser, authorizedUser.getName().getOrig(), connEnv, requestCtx); + // if (!authorizeUser(authorizedUser.asObjectable(), null, authorizedUser.getName().getOrig(), connEnv, requestCtx)){ + // return; + // } + } catch (ObjectNotFoundException | SchemaException | SecurityViolationException + | CommunicationException | ConfigurationException | ExpressionEvaluationException e) { + LOGGER.trace("Exception while authenticating user identified with '{}' to REST service: {}", oid, e.getMessage(), e); + requestCtx.abortWith(Response.status(Status.UNAUTHORIZED).build()); + return; + } - } - private boolean authorizeUser(UserType user, PrismObject proxyUser, String enteredUsername, ConnectionEnvironment connEnv, ContainerRequestContext requestCtx) { - authenticateUser(user.asPrismObject(), enteredUsername, connEnv, requestCtx); - return authorizeUser(AuthorizationConstants.AUTZ_REST_ALL_URL, user, null, enteredUsername, connEnv, requestCtx); - } + } - private void authenticateUser(PrismObject user, String enteredUsername, ConnectionEnvironment connEnv, ContainerRequestContext requestCtx) { - try { - securityContextManager.setupPreAuthenticatedSecurityContext(user); - } catch (SchemaException e) { - securityHelper.auditLoginFailure(enteredUsername, user.asObjectable(), connEnv, "Schema error: "+e.getMessage()); - requestCtx.abortWith(Response.status(Status.BAD_REQUEST).build()); -// return false; - } + m.put(RestServiceUtil.MESSAGE_PROPERTY_TASK_NAME, task); - LOGGER.trace("Authenticated to REST service as {}", user); - } - - private boolean authorizeUser(String authorization, UserType user, PrismObject proxyUser, String enteredUsername, ConnectionEnvironment connEnv, ContainerRequestContext requestCtx) { - Task task = taskManager.createTaskInstance(MidpointRestAuthenticator.class.getName() + ".authorizeUser"); - try { - // authorize for proxy - securityEnforcer.authorize(authorization, null, AuthorizationParameters.Builder.buildObject(proxyUser), null, task, task.getResult()); - } catch (SecurityViolationException e){ - securityHelper.auditLoginFailure(enteredUsername, user, connEnv, "Not authorized"); - requestCtx.abortWith(Response.status(Status.FORBIDDEN).build()); - return false; - } catch (SchemaException | ObjectNotFoundException | ExpressionEvaluationException | CommunicationException | ConfigurationException e) { - securityHelper.auditLoginFailure(enteredUsername, user, connEnv, "Internal error: "+e.getMessage()); - requestCtx.abortWith(Response.status(Status.BAD_REQUEST).build()); - return false; - } - return true; - } + LOGGER.trace("Authorized to use REST service ({})", user); + } - public SecurityContextManager getSecurityContextManager() { - return securityContextManager; - } + private boolean authorizeUser(UserType user, PrismObject proxyUser, String enteredUsername, ConnectionEnvironment connEnv, ContainerRequestContext requestCtx) { + authenticateUser(user.asPrismObject(), enteredUsername, connEnv, requestCtx); + return authorizeUser(AuthorizationConstants.AUTZ_REST_ALL_URL, user, null, enteredUsername, connEnv, requestCtx); + } - public SecurityEnforcer getSecurityEnforcer() { - return securityEnforcer; - } - public ModelService getModel() { - return model; + private void authenticateUser(PrismObject user, String enteredUsername, ConnectionEnvironment connEnv, ContainerRequestContext requestCtx) { + try { + securityContextManager.setupPreAuthenticatedSecurityContext(user); + } catch (SchemaException e) { + securityHelper.auditLoginFailure(enteredUsername, user.asObjectable(), connEnv, "Schema error: "+e.getMessage()); + requestCtx.abortWith(Response.status(Status.BAD_REQUEST).build()); + // return false; } - public TaskManager getTaskManager() { - return taskManager; + LOGGER.trace("Authenticated to REST service as {}", user); + } + + private boolean authorizeUser(String authorization, UserType user, PrismObject proxyUser, String enteredUsername, ConnectionEnvironment connEnv, ContainerRequestContext requestCtx) { + Task task = taskManager.createTaskInstance(MidpointRestAuthenticator.class.getName() + ".authorizeUser"); + try { + // authorize for proxy + securityEnforcer.authorize(authorization, null, AuthorizationParameters.Builder.buildObject(proxyUser), null, task, task.getResult()); + } catch (SecurityViolationException e){ + securityHelper.auditLoginFailure(enteredUsername, user, connEnv, "Not authorized"); + requestCtx.abortWith(Response.status(Status.FORBIDDEN).build()); + return false; + } catch (SchemaException | ObjectNotFoundException | ExpressionEvaluationException | CommunicationException | ConfigurationException e) { + securityHelper.auditLoginFailure(enteredUsername, user, connEnv, "Internal error: "+e.getMessage()); + requestCtx.abortWith(Response.status(Status.BAD_REQUEST).build()); + return false; } + return true; + } + + public SecurityContextManager getSecurityContextManager() { + return securityContextManager; + } + + public SecurityEnforcer getSecurityEnforcer() { + return securityEnforcer; + } + public ModelService getModel() { + return model; + } + + public TaskManager getTaskManager() { + return taskManager; + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestSecurityQuestionsAuthenticator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestSecurityQuestionsAuthenticator.java index 2cd3e517c21..3ac9c7e530f 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestSecurityQuestionsAuthenticator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestSecurityQuestionsAuthenticator.java @@ -109,7 +109,7 @@ protected SecurityQuestionsAuthenticationContext createAuthenticationContext(Aut if (answerNode instanceof MissingNode) { SecurityContextHolder.getContext().setAuthentication(new AnonymousAuthenticationToken("restapi", "REST", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"))); - SearchResultList> users = null; + SearchResultList> users; try { users = searchUser(userName); } finally { @@ -117,19 +117,19 @@ protected SecurityQuestionsAuthenticationContext createAuthenticationContext(Aut } if (users.size() != 1) { - requestCtx.abortWith(Response.status(Status.UNAUTHORIZED).header("WWW-Authenticate", "Security question authentication failed. Incorrect username and/or password").build()); + requestCtx.abortWith(Response.status(Status.UNAUTHORIZED).build()); return null; } PrismObject user = users.get(0); PrismContainer questionAnswerContainer = user.findContainer(SchemaConstants.PATH_SECURITY_QUESTIONS_QUESTION_ANSWER); - if (questionAnswerContainer == null || questionAnswerContainer.isEmpty()){ - requestCtx.abortWith(Response.status(Status.UNAUTHORIZED).header("WWW-Authenticate", "Security question authentication failed. Incorrect username and/or password").build()); + if (questionAnswerContainer == null || questionAnswerContainer.isEmpty()) { + requestCtx.abortWith(Response.status(Status.UNAUTHORIZED).build()); return null; } String questionChallenge = ""; - List questions = null; + List questions; try { SecurityContextHolder.getContext().setAuthentication(new AnonymousAuthenticationToken("restapi", "REST", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"))); questions = getQuestions(user); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/RestServiceUtil.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/RestServiceUtil.java index 79aef91325c..04dea954047 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/RestServiceUtil.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/RestServiceUtil.java @@ -177,8 +177,7 @@ public static Response.ResponseBuilder createResultHeaders(Response.ResponseBuil } public static void createAbortMessage(ContainerRequestContext requestCtx){ - requestCtx.abortWith(Response.status(Status.UNAUTHORIZED) - .header("WWW-Authenticate", RestAuthenticationMethod.BASIC.getMethod() + " realm=\"midpoint\", " + RestAuthenticationMethod.SECURITY_QUESTIONS.getMethod()).build()); + requestCtx.abortWith(Response.status(Status.UNAUTHORIZED).build()); } public static void createSecurityQuestionAbortMessage(ContainerRequestContext requestCtx, String secQChallenge){ diff --git a/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestAbstractRestService.java b/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestAbstractRestService.java index 322f3fbc114..a6d1722b54a 100644 --- a/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestAbstractRestService.java +++ b/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestAbstractRestService.java @@ -332,8 +332,8 @@ public void test017GetUnauthorizedUser() { TestUtil.displayWhen(TEST_NAME); Response response = client.get(); - TestUtil.displayThen(TEST_NAME); - assertStatus(response, 403); + displayThen(TEST_NAME); + assertStatus(response, 401); display("Audit", getDummyAuditService()); getDummyAuditService().assertRecords(1); @@ -642,8 +642,8 @@ public void test131GetUserAdministratorByDarthAdder() { TestUtil.displayWhen(TEST_NAME); Response response = client.get(); - TestUtil.displayThen(TEST_NAME); - assertStatus(response, 403); + displayThen(TEST_NAME); + assertStatus(response, 401); assertNoEmptyResponse(response); display("Audit", getDummyAuditService()); @@ -760,8 +760,8 @@ public void test141GetUserAdministratorByNopasswordBadPassword() { TestUtil.displayWhen(TEST_NAME); Response response = client.get(); - TestUtil.displayThen(TEST_NAME); - assertStatus(response, 403); + displayThen(TEST_NAME); + assertStatus(response, 401); assertNoEmptyResponse(response); display("Audit", getDummyAuditService());