From 62d7f16eda59a888de52410092a791ef2b26b392 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Wed, 1 Apr 2015 19:11:44 +0200 Subject: [PATCH] Introducing AuthorizationException. Minor web service fixes. --- .../xml/ns/public/common/common-3.xsd | 56 +++++ .../exception/AuthorizationException.java | 46 ++++ .../midpoint/model/impl/ModelWebService.java | 49 +++-- .../model/impl/ModelWebServiceRaw.java | 12 +- .../impl/controller/ModelController.java | 7 +- .../midpoint/model/impl/lens/Clockwork.java | 5 +- .../MidpointRestAuthenticationHandler.java | 2 +- ...ringAuthenticationInjectorInterceptor.java | 26 ++- .../security/api/AuthorizationConstants.java | 7 +- .../security/impl/SecurityEnforcerImpl.java | 3 +- .../testing/rest/TestRestService.java | 3 + .../wstest/AbstractWebserviceTest.java | 47 +++- .../wstest/WebserviceSecurityTest.java | 200 ++++++++---------- 13 files changed, 302 insertions(+), 161 deletions(-) create mode 100644 infra/util/src/main/java/com/evolveum/midpoint/util/exception/AuthorizationException.java diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd index f7d4d067e35..39bf7a98f17 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd @@ -8915,6 +8915,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/infra/util/src/main/java/com/evolveum/midpoint/util/exception/AuthorizationException.java b/infra/util/src/main/java/com/evolveum/midpoint/util/exception/AuthorizationException.java new file mode 100644 index 00000000000..a277f6c5520 --- /dev/null +++ b/infra/util/src/main/java/com/evolveum/midpoint/util/exception/AuthorizationException.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015 Evolveum + * + * Licensed 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 com.evolveum.midpoint.util.exception; + +/** + * Exception indicating violation of authorization policies. + * + * @author Radovan Semancik + * + */ +public class AuthorizationException extends SecurityViolationException { + + public AuthorizationException() { + } + + public AuthorizationException(String message) { + super(message); + } + + public AuthorizationException(Throwable cause) { + super(cause); + } + + public AuthorizationException(String message, Throwable cause) { + super(message, cause); + } + + @Override + public String getOperationResultMessage() { + return "Not authorized"; + } + +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebService.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebService.java index c531222629e..1d4b1a6302e 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebService.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebService.java @@ -41,6 +41,7 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.AuthorizationException; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; @@ -80,6 +81,8 @@ import com.evolveum.prism.xml.ns._public.types_3.RawType; import org.apache.commons.lang.StringUtils; +import org.apache.cxf.interceptor.Fault; +import org.apache.wss4j.common.ext.WSSecurityException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -130,7 +133,7 @@ public void getObject(QName objectType, String oid, SelectorQualifiedGetOptionsT return; } catch (Exception ex) { LoggingUtils.logException(LOGGER, "# MODEL getObject() failed", ex); - throw createSystemFault(ex, operationResult); + throwFault(ex, operationResult); } finally { auditLogout(task); } @@ -157,7 +160,7 @@ public void searchObjects(QName objectType, QueryType query, SelectorQualifiedGe objectListHolder.value = listType; } catch (Exception ex) { LoggingUtils.logException(LOGGER, "# MODEL searchObjects() failed", ex); - throw createSystemFault(ex, operationResult); + throwFault(ex, operationResult); } finally { auditLogout(task); } @@ -187,7 +190,9 @@ public ObjectDeltaOperationListType executeChanges(ObjectDeltaListType deltaList return retval; } catch (Exception ex) { LoggingUtils.logException(LOGGER, "# MODEL executeChanges() failed", ex); - throw createSystemFault(ex, operationResult); + throwFault(ex, operationResult); + // notreached + return null; } finally { auditLogout(task); } @@ -210,7 +215,7 @@ public void findShadowOwner(String accountOid, Holder userHolder, Hold return; } catch (Exception ex) { LoggingUtils.logException(LOGGER, "# MODEL findShadowOwner() failed", ex); - throw createSystemFault(ex, operationResult); + throwFault(ex, operationResult); } finally { auditLogout(task); } @@ -227,7 +232,9 @@ public OperationResultType testResource(String resourceOid) throws FaultMessage return handleOperationResult(testResult); } catch (Exception ex) { LoggingUtils.logException(LOGGER, "# MODEL testResource() failed", ex); - throw createSystemFault(ex, null); + throwFault(ex, null); + // notreached + return null; } finally { auditLogout(task); } @@ -243,7 +250,9 @@ public ExecuteScriptsResponseType executeScripts(ExecuteScriptsType parameters) return doExecuteScripts(scriptsToExecute, parameters.getOptions(), task, result); } catch (Exception ex) { LoggingUtils.logException(LOGGER, "# MODEL executeScripts() failed", ex); - throw createSystemFault(ex, null); + throwFault(ex, null); + // notreached + return null; } finally { auditLogout(task); } @@ -359,7 +368,7 @@ public FaultMessage createIllegalArgumentFault(String message) { return new FaultMessage(message, faultType); } - public FaultMessage createSystemFault(Exception ex, OperationResult result) { + public void throwFault(Exception ex, OperationResult result) throws FaultMessage { if (result != null) { result.recordFatalError(ex.getMessage(), ex); } @@ -371,6 +380,12 @@ public FaultMessage createSystemFault(Exception ex, OperationResult result) { faultType = new IllegalArgumentFaultType(); } else if (ex instanceof ObjectAlreadyExistsException){ faultType = new ObjectAlreadyExistsFaultType(); + } else if (ex instanceof AuthorizationException) { + throw new Fault(new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION), + WSSecurityException.ErrorCode.FAILED_AUTHENTICATION.getQName()); + } else if (ex instanceof SecurityViolationException) { + throw new Fault(new WSSecurityException(WSSecurityException.ErrorCode.FAILURE), + WSSecurityException.ErrorCode.FAILURE.getQName()); } else{ faultType = new SystemFaultType(); } @@ -379,7 +394,7 @@ public FaultMessage createSystemFault(Exception ex, OperationResult result) { faultType.setOperationResult(result.createOperationResultType()); } - return new FaultMessage(ex.getMessage(), faultType, ex); + throw new FaultMessage(ex.getMessage(), faultType, ex); } @Override @@ -399,7 +414,9 @@ public TaskType importFromResource(String resourceOid, QName objectClass) } catch (Exception ex) { LoggingUtils.logException(LOGGER, "# MODEL importFromResource() failed", ex); auditLogout(task); - throw createSystemFault(ex, operationResult); + throwFault(ex, operationResult); + // notreached + return null; } } @@ -418,31 +435,31 @@ public TaskType notifyChange(ResourceObjectShadowChangeDescriptionType changeDes } catch (ObjectNotFoundException ex) { LoggingUtils.logException(LOGGER, "# MODEL notifyChange() failed", ex); auditLogout(task); - throw createSystemFault(ex, parentResult); + throwFault(ex, parentResult); } catch (SchemaException ex) { LoggingUtils.logException(LOGGER, "# MODEL notifyChange() failed", ex); auditLogout(task); - throw createSystemFault(ex, parentResult); + throwFault(ex, parentResult); } catch (CommunicationException ex) { LoggingUtils.logException(LOGGER, "# MODEL notifyChange() failed", ex); auditLogout(task); - throw createSystemFault(ex, parentResult); + throwFault(ex, parentResult); } catch (ConfigurationException ex) { LoggingUtils.logException(LOGGER, "# MODEL notifyChange() failed", ex); auditLogout(task); - throw createSystemFault(ex, parentResult); + throwFault(ex, parentResult); } catch (SecurityViolationException ex) { LoggingUtils.logException(LOGGER, "# MODEL notifyChange() failed", ex); auditLogout(task); - throw createSystemFault(ex, parentResult); + throwFault(ex, parentResult); } catch (RuntimeException ex){ LoggingUtils.logException(LOGGER, "# MODEL notifyChange() failed", ex); auditLogout(task); - throw createSystemFault(ex, parentResult); + throwFault(ex, parentResult); } catch (ObjectAlreadyExistsException ex){ LoggingUtils.logException(LOGGER, "# MODEL notifyChange() failed", ex); auditLogout(task); - throw createSystemFault(ex, parentResult); + throwFault(ex, parentResult); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebServiceRaw.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebServiceRaw.java index 77433a161c8..150b6dc0850 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebServiceRaw.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebServiceRaw.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Evolveum + * Copyright (c) 2010-2015 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -189,7 +189,9 @@ public DOMSource invokeAllowingFaults(DOMSource request) throws FaultMessage { throw ws.createIllegalArgumentFault("Unsupported request type: " + requestObject); } } catch (SchemaException e) { - throw createSystemFault(e, operationResultTypeHolder.value); + throwFault(e, operationResultTypeHolder.value); + // not reached + return null; } // brutal hack for MID-2001 (serializing and parsing eliminates the problem!) @@ -221,11 +223,11 @@ private String getStackTraceAsString(FaultMessage faultMessage) { return sw.toString(); } - private FaultMessage createSystemFault(Exception ex, OperationResultType resultType) { + private void throwFault(Exception ex, OperationResultType resultType) throws FaultMessage { if (resultType != null) { - return ws.createSystemFault(ex, OperationResult.createOperationResult(resultType)); + ws.throwFault(ex, OperationResult.createOperationResult(resultType)); } else { - return ws.createSystemFault(ex, null); + ws.throwFault(ex, null); } } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java index 011b1baa20e..41b73bbccb0 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java @@ -138,6 +138,7 @@ import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.DisplayableValue; +import com.evolveum.midpoint.util.exception.AuthorizationException; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; @@ -1920,12 +1921,12 @@ private void postProcessObject(PrismObject object, Get LOGGER.trace("Security constrains for {}:\n{}", object, securityConstraints==null?"null":securityConstraints.debugDump()); } if (securityConstraints == null) { - throw new SecurityViolationException("Access denied"); + throw new AuthorizationException("Access denied"); } AuthorizationDecisionType globalDecision = securityConstraints.getActionDecision(ModelAuthorizationAction.READ.getUrl(), null); if (globalDecision == AuthorizationDecisionType.DENY) { // shortcut - throw new SecurityViolationException("Access denied"); + throw new AuthorizationException("Access denied"); } if (globalDecision == AuthorizationDecisionType.ALLOW && securityConstraints.hasNoItemDecisions()) { // shortcut, nothing to do @@ -1933,7 +1934,7 @@ private void postProcessObject(PrismObject object, Get removeDeniedItems((List)object.getValue().getItems(), securityConstraints, globalDecision); if (object.isEmpty()) { // let's make it explicit - throw new SecurityViolationException("Access denied"); + throw new AuthorizationException("Access denied"); } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Clockwork.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Clockwork.java index c8aebb69a02..72311a7ba7d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Clockwork.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Clockwork.java @@ -70,6 +70,7 @@ import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.MiscUtil; +import com.evolveum.midpoint.util.exception.AuthorizationException; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; @@ -916,13 +917,13 @@ private ObjectSecurityConstraints a if (assignmentItemDecision == AuthorizationDecisionType.ALLOW) { // Nothing to do, operation is allowed for all values } else if (assignmentItemDecision == AuthorizationDecisionType.DENY) { - throw new SecurityViolationException("Access denied"); + throw new AuthorizationException("Access denied"); } else { AuthorizationDecisionType actionDecision = securityConstraints.getActionDecision(operationUrl, AuthorizationPhaseType.REQUEST); if (actionDecision == AuthorizationDecisionType.ALLOW) { // Nothing to do, operation is allowed for all values } else if (actionDecision == AuthorizationDecisionType.DENY) { - throw new SecurityViolationException("Access denied"); + throw new AuthorizationException("Access denied"); } else { // No explicit decision for assignment modification yet // process each assignment individually diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestAuthenticationHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestAuthenticationHandler.java index f7f2f1e981d..8a9ed19277e 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestAuthenticationHandler.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestAuthenticationHandler.java @@ -175,7 +175,7 @@ public void handleRequest(Message m, ContainerRequestContext requestCtx) { try { - securityEnforcer.authorize(AuthorizationConstants.AUTZ_REST_URL, null, null, null, null, null, authorizeResult); + securityEnforcer.authorize(AuthorizationConstants.AUTZ_REST_ALL_URL, null, null, null, null, null, authorizeResult); } catch (SecurityViolationException e){ securityHelper.auditLoginFailure(username, "Not authorized", SchemaConstants.CHANNEL_REST_URI); requestCtx.abortWith(Response.status(403).header("WWW-Authenticate", "Basic").build()); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/SpringAuthenticationInjectorInterceptor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/SpringAuthenticationInjectorInterceptor.java index 72ec9ce9298..f9a17363ef3 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/SpringAuthenticationInjectorInterceptor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/SpringAuthenticationInjectorInterceptor.java @@ -157,11 +157,13 @@ public void handleMessage(SoapMessage message) throws Fault { securityHelper.auditLoginFailure(username, "SOAP error: "+e.getMessage(), SchemaConstants.CHANNEL_WEB_SERVICE_URI); throw new Fault(e); } - String action = QNameUtil.qNameToUri(new QName(AuthorizationConstants.NS_AUTHORIZATION_WS, operationName)); - LOGGER.trace("Determining authorization for web service operation {} (action: {})", operationName, action); - boolean isAuthorized; + + // AUTHORIZATION + + boolean isAuthorized; try { - isAuthorized = securityEnforcer.isAuthorized(action, AuthorizationPhaseType.REQUEST, null, null, null, null); + isAuthorized = securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_WS_ALL_URL, AuthorizationPhaseType.REQUEST, null, null, null, null); + LOGGER.trace("Determined authorization for web service access (action: {}): {}", AuthorizationConstants.AUTZ_WS_ALL_URL, isAuthorized); } catch (SchemaException e) { LOGGER.debug("Access to web service denied for user '{}': schema error: {}", new Object[]{username, e.getMessage(), e}); @@ -169,6 +171,19 @@ public void handleMessage(SoapMessage message) throws Fault { securityHelper.auditLoginFailure(username, "Schema error: "+e.getMessage(), SchemaConstants.CHANNEL_WEB_SERVICE_URI); throw createFault(WSSecurityException.ErrorCode.FAILURE); } + if (!isAuthorized) { + String action = QNameUtil.qNameToUri(new QName(AuthorizationConstants.NS_AUTHORIZATION_WS, operationName)); + try { + isAuthorized = securityEnforcer.isAuthorized(action, AuthorizationPhaseType.REQUEST, null, null, null, null); + LOGGER.trace("Determined authorization for web service operation {} (action: {}): {}", operationName, action, isAuthorized); + } catch (SchemaException e) { + LOGGER.debug("Access to web service denied for user '{}': schema error: {}", + new Object[]{username, e.getMessage(), e}); + message.setContextualProperty(SecurityHelper.CONTEXTUAL_PROPERTY_AUDITED_NAME, true); + securityHelper.auditLoginFailure(username, "Schema error: "+e.getMessage(), SchemaConstants.CHANNEL_WEB_SERVICE_URI); + throw createFault(WSSecurityException.ErrorCode.FAILURE); + } + } if (!isAuthorized) { LOGGER.debug("Access to web service denied for user '{}': not authorized", new Object[]{username}); @@ -191,6 +206,9 @@ public void handleMessage(SoapMessage message) throws Fault { throw createFault(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION); } + // Avoid auditing login attempt again if the operation fails on internal authorization + message.setContextualProperty(SecurityHelper.CONTEXTUAL_PROPERTY_AUDITED_NAME, true); + LOGGER.debug("Access to web service allowed for user '{}'", username); } diff --git a/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/AuthorizationConstants.java b/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/AuthorizationConstants.java index b06827d7a41..ca0b14d3c19 100644 --- a/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/AuthorizationConstants.java +++ b/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/AuthorizationConstants.java @@ -36,8 +36,11 @@ public class AuthorizationConstants { public static final QName AUTZ_ALL_QNAME = new QName(NS_AUTHORIZATION, "all"); public static final String AUTZ_ALL_URL = QNameUtil.qNameToUri(AUTZ_ALL_QNAME); - public static final QName AUTZ_REST_QNAME = new QName(NS_AUTHORIZATION_REST, "all"); - public static final String AUTZ_REST_URL = QNameUtil.qNameToUri(AUTZ_REST_QNAME); + public static final QName AUTZ_REST_ALL_QNAME = new QName(NS_AUTHORIZATION_REST, "all"); + public static final String AUTZ_REST_ALL_URL = QNameUtil.qNameToUri(AUTZ_REST_ALL_QNAME); + + public static final QName AUTZ_WS_ALL_QNAME = new QName(NS_AUTHORIZATION_WS, "all"); + public static final String AUTZ_WS_ALL_URL = QNameUtil.qNameToUri(AUTZ_WS_ALL_QNAME); // public static final QName AUTZ_DEVEL_QNAME = new QName(NS_AUTHORIZATION, "devel"); public static final String AUTZ_NO_ACCESS_URL = NS_AUTHORIZATION + "#noAccess"; diff --git a/repo/security-impl/src/main/java/com/evolveum/midpoint/security/impl/SecurityEnforcerImpl.java b/repo/security-impl/src/main/java/com/evolveum/midpoint/security/impl/SecurityEnforcerImpl.java index a9f31e34c97..31b487c174d 100644 --- a/repo/security-impl/src/main/java/com/evolveum/midpoint/security/impl/SecurityEnforcerImpl.java +++ b/repo/security-impl/src/main/java/com/evolveum/midpoint/security/impl/SecurityEnforcerImpl.java @@ -73,6 +73,7 @@ import com.evolveum.midpoint.security.api.SecurityUtil; import com.evolveum.midpoint.security.api.UserProfileService; import com.evolveum.midpoint.util.QNameUtil; +import com.evolveum.midpoint.util.exception.AuthorizationException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.exception.SystemException; @@ -342,7 +343,7 @@ public void authorize(String operat if (!allow) { String username = getQuotedUsername(principal); LOGGER.error("User {} not authorized for operation {}", username, operationUrl); - SecurityViolationException e = new SecurityViolationException("User "+username+" not authorized for operation " + AuthorizationException e = new AuthorizationException("User "+username+" not authorized for operation " +operationUrl); // +":\n"+((MidPointPrincipal)principal).debugDump()); result.recordFatalError(e.getMessage(), e); diff --git a/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestRestService.java b/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestRestService.java index 2e2335bcf1a..38c523b2dca 100644 --- a/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestRestService.java +++ b/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestRestService.java @@ -187,6 +187,9 @@ public static void destroy() throws Exception { public TestRestService() { super(); } + + // TODO: user with no password + // TODO: disabled user @Test public void test001GetUserAdministrator() { diff --git a/testing/wstest/src/test/java/com/evolveum/midpoint/testing/wstest/AbstractWebserviceTest.java b/testing/wstest/src/test/java/com/evolveum/midpoint/testing/wstest/AbstractWebserviceTest.java index c0ecd9255be..145031ac9bf 100644 --- a/testing/wstest/src/test/java/com/evolveum/midpoint/testing/wstest/AbstractWebserviceTest.java +++ b/testing/wstest/src/test/java/com/evolveum/midpoint/testing/wstest/AbstractWebserviceTest.java @@ -101,7 +101,7 @@ public abstract class AbstractWebserviceTest { public static final File COMMON_DIR = new File("src/test/resources/common"); public static final String ENDPOINT = "http://localhost:8080/midpoint/ws/model-3"; - public static final String USER_ADMINISTRATOR_OID = "00000000-0000-0000-0000-000000000002"; + public static final String USER_ADMINISTRATOR_OID = SystemObjectsType.SYSTEM_CONFIGURATION.value(); public static final String USER_ADMINISTRATOR_USERNAME = "administrator"; public static final String USER_ADMINISTRATOR_PASSWORD = "5ecr3t"; @@ -320,21 +320,24 @@ protected static Element parseElement(String stringXml) throws SAXException, IOE * Clean the repository after tests. Preserves user administrator * */ protected void cleanRepository() throws FaultMessage { - Holder resultHolder = new Holder(); + cleanObjects(UserType.class, SystemObjectsType.USER_ADMINISTRATOR.value()); + cleanObjects(RoleType.class, SystemObjectsType.ROLE_SUPERUSER.value(), SystemObjectsType.ROLE_END_USER.value()); + } + + private void cleanObjects(Class type, String... protectedOids) throws FaultMessage { + Holder resultHolder = new Holder(); Holder objectListHolder = new Holder(); PagingType paging = new PagingType(); - modelPort.searchObjects(getTypeQName(UserType.class), null, null, objectListHolder, resultHolder); + modelPort.searchObjects(getTypeQName(type), null, null, objectListHolder, resultHolder); + List protectedOidList = Arrays.asList(protectedOids); ObjectListType objectList = objectListHolder.value; - List objects = objectList.getObject(); - - for(int i = 0; i < objects.size(); i++){ - UserType user = (UserType) objects.get(i); - if(!USER_ADMINISTRATOR_OID.equals(user.getOid())) { - display("Deleting user "+ModelClientUtil.toString(user)); - deleteObject(UserType.class, user.getOid()); - } + for (ObjectType object: objectList.getObject()) { + if (!protectedOidList.contains(object.getOid())) { + display("Deleting "+type.getSimpleName()+" "+ModelClientUtil.toString(object)); + deleteObject(type, object.getOid()); + } } } @@ -360,6 +363,28 @@ protected String addObject(O object) throws FaultMessage assertSuccess(deltaOpList); return deltaOpList.getDeltaOperation().get(0).getObjectDelta().getOid(); } + + protected void assertObjectCount(Class type, int expCount) throws FaultMessage { + assertEquals("Unexpected count of "+type.getSimpleName(), expCount, countObjects(type)); + } + + protected int countObjects(Class type) throws FaultMessage { + Holder resultHolder = new Holder(); + Holder objectListHolder = new Holder(); + modelPort.searchObjects(getTypeQName(type), null, null, objectListHolder, resultHolder); + assertSuccess(resultHolder.value); + Integer count = objectListHolder.value.getCount(); + if (count != null) { + assertEquals("Wrong count", (Integer)objectListHolder.value.getObject().size(), count); + } + return objectListHolder.value.getObject().size(); + } + + + protected void assertUser(UserType user, String expOid, String expName) { + assertEquals("Wrong user oid", expOid, user.getOid()); + assertEquals("Wrong user name", expName, ModelClientUtil.getOrig(user.getName())); + } protected void assertUser(UserType user, String expOid, String expName, String expGivenName, String expFamilyName) { assertEquals("Wrong user oid", expOid, user.getOid()); diff --git a/testing/wstest/src/test/java/com/evolveum/midpoint/testing/wstest/WebserviceSecurityTest.java b/testing/wstest/src/test/java/com/evolveum/midpoint/testing/wstest/WebserviceSecurityTest.java index 09a1f9b3865..07f7d83a604 100644 --- a/testing/wstest/src/test/java/com/evolveum/midpoint/testing/wstest/WebserviceSecurityTest.java +++ b/testing/wstest/src/test/java/com/evolveum/midpoint/testing/wstest/WebserviceSecurityTest.java @@ -43,6 +43,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemObjectsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; @@ -371,6 +372,7 @@ public void test111GetConfigGoodPasswordText() throws Exception { modelPort.getObject(getTypeQName(SystemConfigurationType.class), SystemObjectsType.SYSTEM_CONFIGURATION.value(), null, objectHolder, resultHolder); + // THEN tailer.tail(); assertAuditLoginLogout(tailer); assertAuditIds(tailer); @@ -453,7 +455,6 @@ public void test122GetConfigAsNobodyEmptyPasswordDigest() throws Exception { tailer.tail(); assertAuditLoginFailed(tailer, "could not be authenticated or authorized"); - } @Test @@ -480,124 +481,91 @@ public void test122GetConfigAsNobodyGoodPasswordDigest() throws Exception { tailer.tail(); assertAuditLoginFailed(tailer, "Not authorized"); + } + + @Test + public void test130AddRolesAndUsersAsAdministrator() throws Exception { + final String TEST_NAME = "test130AddRolesAndUsersAsAdministrator"; + displayTestTitle(TEST_NAME); + + modelPort = createModelPort(USER_ADMINISTRATOR_USERNAME, USER_ADMINISTRATOR_PASSWORD, WSConstants.PW_DIGEST); + + RoleType role = ModelClientUtil.unmarshallFile(ROLE_WS_FILE); + addObject(role); + + role = ModelClientUtil.unmarshallFile(ROLE_READER_FILE); + addObject(role); + + UserType user = ModelClientUtil.unmarshallFile(USER_CYCLOPS_FILE); + String userCyclopsOid = addObject(user); + + user = ModelClientUtil.unmarshallFile(USER_SOMEBODY_FILE); + addObject(user); + // GET user + UserType userAfter = getObject(UserType.class, userCyclopsOid); + assertUser(userAfter, userCyclopsOid, USER_CYCLOPS_USERNAME); + + assertObjectCount(UserType.class, 4); + assertObjectCount(RoleType.class, 4); } -// -// /** -// * In this test, we first create and add user with admin privileges and empty password. -// * Next step is to try to use webservice with this user, so we create model port with -// * this user and set empty logon password. -// * -// * Exception is expected -// * */ -// @Test(expectedExceptions = Exception.class) -// public void wsSecurity02() throws FaultMessage, JAXBException{ -// modelPort = createModelPort(); -// configurationType = getConfiguration(modelPort); -// File file = new File(SECURITY_DIR_NAME + USER_TEST_2_FILENAME); -// UserType user = (UserType)unmarshallFromFile(file, PACKAGE_COMMON_2A); -// -// modelPort.addObject(user, new Holder(), new Holder()); -// modelPort.deleteObject(getTypeUri(SystemConfigurationType.class), configurationType.getOid()); -// -// file = new File(SECURITY_DIR_NAME + SYSTEM_CONFIG_FILENAME); -// SystemConfigurationType config = (SystemConfigurationType)unmarshallFromFile(file, PACKAGE_COMMON_2A); -// modelPort.addObject(config, new Holder(), new Holder()); -// -// file = new File(SECURITY_DIR_NAME + USER_TEST_2_CLEAN_PASS_FILENAME); -// ObjectModificationType objectChange = (ObjectModificationType)unmarshallFromFile(file, PACKAGE_API_TYPES_2); -// modelPort.modifyObject(getTypeUri(UserType.class), objectChange); -// -// modelPort.deleteObject(getTypeUri(SystemConfigurationType.class), system_config_oid); -// file = new File(SECURITY_DIR_NAME + SYSTEM_CONFIG_NORMAL_FILENAME); -// config = (SystemConfigurationType)unmarshallFromFile(file, PACKAGE_COMMON_2A); -// modelPort.addObject(config, new Holder(), new Holder()); -// -// SecurityClientPasswordHandler.setClientPassword(""); -// modelPort = createModelPort("Anakin2", "wsSecurity02"); -// modelPort.getObject(getTypeUri(UserType.class), test_user_oid_2, new OperationOptionsType(), new Holder(), new Holder()); -// } -// -// /** -// * In this test, we try to establish connection without webservice token -// * */ -// @Test(expectedExceptions = Exception.class) -// public void wsSecurity03() throws FaultMessage{ -// String endpointUrl = "http://localhost:8080/midpoint/model/model-1"; -// -// LOGGER.info("WSSecurityTests: #createModelPort: Endpoint URL: " + endpointUrl + " for test: wsSecurity03"); -// -// ModelService modelService = new ModelService(); -// ModelPortType modelPort = modelService.getModelPort(); -// BindingProvider bp = (BindingProvider)modelPort; -// Map requestContext = bp.getRequestContext(); -// requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointUrl); -// -// org.apache.cxf.endpoint.Client client = ClientProxy.getClient(modelPort); -// org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint(); -// -// Map outProps = new HashMap(); -// outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN); -// -// //Here we don't send token to webService -// //outProps.put(WSHandlerConstants.USER, username); -// //outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST); -// //outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, SecurityClientPasswordHandler.class.getName()); -// -// WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps); -// cxfEndpoint.getOutInterceptors().add(wssOut); -// -// configurationType = getConfiguration(modelPort); -// } -// -// /** -// * Here will be test with user with non-existing username -// * */ -// @Test(expectedExceptions = Exception.class) -// public void wsSecurity04() throws FaultMessage{ -// modelPort = createModelPort("Not Existing user", "wsSecurity04"); -// configurationType = getConfiguration(modelPort); -// } -// -// /** -// * In this test, we test, if user with no admin privilages, but correct credentials is able to -// * log on midpoint webservices and use them. So, first we create non-admin user and then we -// * simply try to use we operations with him -// * -// * */ -// @Test(expectedExceptions = Exception.class) -// public void wsSecurity05() throws JAXBException, FaultMessage{ -// modelPort = createModelPort(); -// File file = new File(SECURITY_DIR_NAME + USER_TEST_5_FILENAME); -// UserType user = (UserType)unmarshallFromFile(file, PACKAGE_COMMON_2A); -// modelPort.addObject(user, new Holder(), new Holder()); -// -// SecurityClientPasswordHandler.setClientPassword(UNIVERSAL_USER_PASSWORD); -// modelPort = createModelPort("Anakin5", "wsSecurity05"); -// configurationType = getConfiguration(modelPort); -// } -// -// /** -// * In this test, we test disabled user accessibility to midpoint webservice. To prevent -// * other potential faults, test user has enabled admin privileges and provided password -// * is correct -// * -// * Exception is expected -// * */ -// @Test(expectedExceptions = Exception.class) -// public void wsSecurity06() throws JAXBException, FaultMessage{ -// modelPort = createModelPort(); -// File file = new File(SECURITY_DIR_NAME + USER_TEST_6_FILENAME); -// UserType user = (UserType)unmarshallFromFile(file, PACKAGE_COMMON_2A); -// modelPort.addObject(user, new Holder(), new Holder()); -// -// SecurityClientPasswordHandler.setClientPassword(UNIVERSAL_USER_PASSWORD); -// modelPort = createModelPort("Anakin6", "wsSecurity06"); -// configurationType = getConfiguration(modelPort); -// } -//} -// + @Test + public void test131GetConfigAsCyclopsGoodPasswordDigest() throws Exception { + final String TEST_NAME = "test131GetConfigAsCyclopsGoodPasswordDigest"; + displayTestTitle(TEST_NAME); + + modelPort = createModelPort(USER_CYCLOPS_USERNAME, USER_CYCLOPS_PASSWORD, WSConstants.PW_DIGEST); + + Holder objectHolder = new Holder(); + Holder resultHolder = new Holder(); + + LogfileTestTailer tailer = createLogTailer(); + + // WHEN + try { + modelPort.getObject(getTypeQName(SystemConfigurationType.class), SystemObjectsType.SYSTEM_CONFIGURATION.value(), + null, objectHolder, resultHolder); + + AssertJUnit.fail("Unexpected success"); + + } catch (SOAPFaultException e) { + assertSoapFault(e, "FailedAuthentication", "could not be authenticated or authorized"); + } + + tailer.tail(); + displayAudit(tailer); + assertAuditLoginLogout(tailer); + } + + @Test + public void test132GetConfigAsSomebodyGoodPasswordDigest() throws Exception { + final String TEST_NAME = "test132GetConfigAsSomebodyGoodPasswordDigest"; + displayTestTitle(TEST_NAME); + + LogfileTestTailer tailer = createLogTailer(); + modelPort = createModelPort(USER_SOMEBODY_USERNAME, USER_SOMEBODY_PASSWORD, WSConstants.PW_DIGEST); + + Holder objectHolder = new Holder(); + Holder resultHolder = new Holder(); + + /// WHEN + modelPort.getObject(getTypeQName(SystemConfigurationType.class), SystemObjectsType.SYSTEM_CONFIGURATION.value(), + null, objectHolder, resultHolder); + + // THEN + tailer.tail(); + assertAuditLoginLogout(tailer); + assertAuditIds(tailer); + tailer.assertAudit(2); + } + + + // TODO: user with no password + + // TODO: disabled user + + }