You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2018/10/01 15:04:47 UTC

[6/6] syncope git commit: [SYNCOPE-1377] Added JAX-RS ContainerRequestFilter to check X-Syncope-Domain provided value

[SYNCOPE-1377] Added JAX-RS ContainerRequestFilter to check X-Syncope-Domain provided value


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/da918686
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/da918686
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/da918686

Branch: refs/heads/master
Commit: da91868697e61412ef53cdee717bc82b6db405bc
Parents: 25d6c1f
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Mon Oct 1 17:01:49 2018 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Mon Oct 1 17:04:33 2018 +0200

----------------------------------------------------------------------
 .../syncope/core/rest/cxf/AddETagFilter.java    |  2 +-
 .../core/rest/cxf/CheckDomainFilter.java        | 81 ++++++++++++++++++++
 .../src/main/resources/restCXFContext.xml       |  2 +
 .../core/spring/security/AuthContextUtils.java  | 15 ++--
 .../src/main/resources/jboss/restCXFContext.xml |  2 +
 .../syncope/fit/core/MultitenancyITCase.java    | 17 ++++
 6 files changed, 110 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/da918686/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AddETagFilter.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AddETagFilter.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AddETagFilter.java
index dc6f0e6..145bea2 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AddETagFilter.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AddETagFilter.java
@@ -31,7 +31,7 @@ import org.apache.syncope.common.lib.to.EntityTO;
 import org.apache.syncope.common.lib.to.ProvisioningResult;
 
 /**
- * Adds the <tt>ETag</tt> header to any response containing an instance of {@link AbstractAnnotatedBean} as entity.
+ * Adds the {@code ETag} header to any response containing an instance of {@link AbstractAnnotatedBean} as entity.
  * The actual ETag value is computed on the basis of last change date (or creation date if not available).
  */
 @Provider

http://git-wip-us.apache.org/repos/asf/syncope/blob/da918686/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/CheckDomainFilter.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/CheckDomainFilter.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/CheckDomainFilter.java
new file mode 100644
index 0000000..f2aabad
--- /dev/null
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/CheckDomainFilter.java
@@ -0,0 +1,81 @@
+/*
+ * 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.syncope.core.rest.cxf;
+
+import java.io.IOException;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.container.PreMatching;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.to.ErrorTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.core.persistence.api.dao.DomainDAO;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * Checks that requested Domain exists.
+ */
+@Provider
+@PreMatching
+public class CheckDomainFilter implements ContainerRequestFilter {
+
+    @Autowired
+    private DomainDAO domainDAO;
+
+    @Override
+    public void filter(final ContainerRequestContext reqContext) throws IOException {
+        final String domain = reqContext.getHeaderString(RESTHeaders.DOMAIN);
+        if (domain != null && !SyncopeConstants.MASTER_DOMAIN.equals(domain)) {
+            AuthContextUtils.execWithAuthContext(
+                    SyncopeConstants.MASTER_DOMAIN, new AuthContextUtils.Executable<Void>() {
+
+                @Override
+                public Void exec() {
+                    if (domainDAO.find(domain) == null) {
+                        String message = "Domain '" + domain + "' not available";
+
+                        ErrorTO error = new ErrorTO();
+                        error.setStatus(Response.Status.NOT_FOUND.getStatusCode());
+                        error.setType(ClientExceptionType.NotFound);
+                        error.getElements().add(message);
+
+                        reqContext.abortWith(Response.status(Response.Status.NOT_FOUND).
+                                entity(error).
+                                header(HttpHeaders.CONTENT_TYPE,
+                                        reqContext.getAcceptableMediaTypes().isEmpty()
+                                        ? MediaType.APPLICATION_JSON
+                                        : reqContext.getAcceptableMediaTypes().get(0).toString()).
+                                header(RESTHeaders.ERROR_CODE,
+                                        ClientExceptionType.NotFound.name()).
+                                header(RESTHeaders.ERROR_INFO,
+                                        ClientExceptionType.NotFound.getInfoHeaderValue(message)).
+                                build());
+                    }
+                    return null;
+                }
+            });
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/da918686/core/rest-cxf/src/main/resources/restCXFContext.xml
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/resources/restCXFContext.xml b/core/rest-cxf/src/main/resources/restCXFContext.xml
index dd3ff18..b68b33f 100644
--- a/core/rest-cxf/src/main/resources/restCXFContext.xml
+++ b/core/rest-cxf/src/main/resources/restCXFContext.xml
@@ -90,6 +90,7 @@ under the License.
   
   <bean id="searchContextProvider" class="org.apache.cxf.jaxrs.ext.search.SearchContextProvider"/>
     
+  <bean id="checkDomainFilter" class="org.apache.syncope.core.rest.cxf.CheckDomainFilter"/>
   <bean id="addDomainFilter" class="org.apache.syncope.core.rest.cxf.AddDomainFilter"/>
   <bean id="addETagFilter" class="org.apache.syncope.core.rest.cxf.AddETagFilter"/>
   
@@ -165,6 +166,7 @@ under the License.
       <ref bean="yamlProvider"/>
       <ref bean="exceptionMapper"/>
       <ref bean="searchContextProvider"/>
+      <ref bean="checkDomainFilter"/>
       <ref bean="addDomainFilter"/>
       <ref bean="addETagFilter"/>
       <ref bean="wadlGenerator"/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/da918686/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthContextUtils.java
----------------------------------------------------------------------
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthContextUtils.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthContextUtils.java
index 6bc5fdb..ee99056 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthContextUtils.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthContextUtils.java
@@ -98,7 +98,7 @@ public final class AuthContextUtils {
         return domainKey;
     }
 
-    private static void setFakeAuth(final String domain) {
+    private static Authentication getFakeAuth(final String domain) {
         List<GrantedAuthority> authorities = EntitlementsHolder.getInstance().getValues().stream().
                 map(entitlement -> new SyncopeGrantedAuthority(entitlement, SyncopeConstants.ROOT_REALM)).
                 collect(Collectors.toList());
@@ -107,20 +107,19 @@ public final class AuthContextUtils {
                 new User(ApplicationContextProvider.getBeanFactory().getBean("adminUser", String.class),
                         "FAKE_PASSWORD", authorities), "FAKE_PASSWORD", authorities);
         auth.setDetails(new SyncopeAuthenticationDetails(domain));
-        SecurityContextHolder.getContext().setAuthentication(auth);
+        return auth;
     }
 
-    public static <T> T execWithAuthContext(final String domainKey, final Executable<T> executable) {
-        SecurityContext ctx = SecurityContextHolder.getContext();
-        setFakeAuth(domainKey);
+    public static <T> T execWithAuthContext(final String domain, final Executable<T> executable) {
+        Authentication original = SecurityContextHolder.getContext().getAuthentication();
+        SecurityContextHolder.getContext().setAuthentication(getFakeAuth(domain));
         try {
             return executable.exec();
         } catch (Throwable t) {
-            LOG.debug("Error during execution with domain {} context", domainKey, t);
+            LOG.debug("Error during execution with domain {} context", domain, t);
             throw t;
         } finally {
-            SecurityContextHolder.clearContext();
-            SecurityContextHolder.setContext(ctx);
+            SecurityContextHolder.getContext().setAuthentication(original);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/da918686/fit/core-reference/src/main/resources/jboss/restCXFContext.xml
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/resources/jboss/restCXFContext.xml b/fit/core-reference/src/main/resources/jboss/restCXFContext.xml
index b06589b..7bb4b94 100644
--- a/fit/core-reference/src/main/resources/jboss/restCXFContext.xml
+++ b/fit/core-reference/src/main/resources/jboss/restCXFContext.xml
@@ -90,6 +90,7 @@ under the License.
   
   <bean id="searchContextProvider" class="org.apache.cxf.jaxrs.ext.search.SearchContextProvider"/>
     
+  <bean id="checkDomainFilter" class="org.apache.syncope.core.rest.cxf.CheckDomainFilter"/>
   <bean id="addDomainFilter" class="org.apache.syncope.core.rest.cxf.AddDomainFilter"/>
   <bean id="addETagFilter" class="org.apache.syncope.core.rest.cxf.AddETagFilter"/>
   
@@ -179,6 +180,7 @@ under the License.
       <ref bean="yamlProvider"/>
       <ref bean="exceptionMapper"/>
       <ref bean="searchContextProvider"/>
+      <ref bean="checkDomainFilter"/>
       <ref bean="addDomainFilter"/>
       <ref bean="addETagFilter"/>
       <ref bean="wadlGenerator"/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/da918686/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
index e07c30f..c088bd6 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
@@ -21,6 +21,7 @@ package org.apache.syncope.fit.core;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
 import java.util.List;
@@ -31,6 +32,7 @@ import javax.ws.rs.core.Response;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
+import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.ConnInstanceTO;
 import org.apache.syncope.common.lib.to.ItemTO;
@@ -45,6 +47,7 @@ import org.apache.syncope.common.lib.to.ExecTO;
 import org.apache.syncope.common.lib.to.PushTaskTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.LoggerType;
 import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.common.lib.types.ExecStatus;
@@ -63,6 +66,7 @@ import org.apache.syncope.common.rest.api.service.ReconciliationService;
 import org.apache.syncope.common.rest.api.service.ResourceService;
 import org.apache.syncope.common.rest.api.service.SchemaService;
 import org.apache.syncope.common.rest.api.service.TaskService;
+import org.apache.syncope.common.rest.api.service.UserSelfService;
 import org.apache.syncope.common.rest.api.service.UserService;
 import org.apache.syncope.fit.AbstractITCase;
 import org.identityconnectors.framework.common.objects.ObjectClass;
@@ -241,4 +245,17 @@ public class MultitenancyITCase extends AbstractITCase {
             adminClient.getService(ResourceService.class).delete(resource.getKey());
         }
     }
+
+    @Test
+    public void issueSYNCOPE1377() {
+        try {
+            new SyncopeClientFactoryBean().setAddress(ADDRESS).setDomain("NotExisting").create().
+                    getService(UserSelfService.class).
+                    create(UserITCase.getUniqueSampleTO("syncope1377@syncope.apache.org"), true);
+            fail("This should not happen");
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.NotFound, e.getType());
+            assertTrue(e.getMessage().contains("NotExisting"));
+        }
+    }
 }