cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From serg...@apache.org
Subject cxf git commit: [CXF-6663] Prototyping a scope based access control code
Date Tue, 10 Nov 2015 12:11:46 GMT
Repository: cxf
Updated Branches:
  refs/heads/master 9dd00304c -> 64afe0840


[CXF-6663] Prototyping a scope based access control code


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

Branch: refs/heads/master
Commit: 64afe0840aeb10209fe9a318391fcf72f5a3c4cc
Parents: 9dd0030
Author: Sergey Beryozkin <sberyozkin@gmail.com>
Authored: Tue Nov 10 12:11:31 2015 +0000
Committer: Sergey Beryozkin <sberyozkin@gmail.com>
Committed: Tue Nov 10 12:11:31 2015 +0000

----------------------------------------------------------------------
 .../oauth2/filters/ConfidentialClient.java      |  39 +++++
 .../oauth2/filters/OAuthScopesFilter.java       | 150 +++++++++++++++++++
 .../cxf/rs/security/oauth2/filters/Scopes.java  |  44 ++++++
 3 files changed, 233 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/64afe084/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/ConfidentialClient.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/ConfidentialClient.java
b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/ConfidentialClient.java
new file mode 100644
index 0000000..fcd784a
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/ConfidentialClient.java
@@ -0,0 +1,39 @@
+/**
+ * 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.cxf.rs.security.oauth2.filters;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Inherited
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+/**
+ * Indicates that only OAuth2 confidential clients can invoke a given resource method.
+ * Confidential clients are less likely to have their access tokens lost or stolen due
+ * to them being generally more secure than public clients which can not keep their client

+ * secrets.
+ */
+public @interface ConfidentialClient {
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/64afe084/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/OAuthScopesFilter.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/OAuthScopesFilter.java
b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/OAuthScopesFilter.java
new file mode 100644
index 0000000..f26cf78
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/OAuthScopesFilter.java
@@ -0,0 +1,150 @@
+/**
+ * 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.cxf.rs.security.oauth2.filters;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.core.Context;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.ClassHelper;
+import org.apache.cxf.jaxrs.ext.MessageContext;
+import org.apache.cxf.jaxrs.utils.ExceptionUtils;
+import org.apache.cxf.rs.security.oauth2.common.OAuthContext;
+import org.apache.cxf.rs.security.oauth2.common.OAuthPermission;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthContextUtils;
+
+
+public class OAuthScopesFilter implements ContainerRequestFilter {
+
+    private static final Logger LOG = LogUtils.getL7dLogger(OAuthScopesFilter.class);
+    private static final Set<String> SKIP_METHODS;
+    static {
+        SKIP_METHODS = new HashSet<String>();
+        SKIP_METHODS.addAll(Arrays.asList(
+            new String[] {"wait", "notify", "notifyAll", 
+                          "equals", "toString", "hashCode"}));
+    }
+
+    @Context
+    private MessageContext mc;
+    private Map<String, List<String>> scopesMap = new HashMap<String, List<String>>();
+    private Map<String, Boolean> scopesMatchAllMap = new HashMap<String, Boolean>();
+    private Set<String> confidentialClientMethods = new HashSet<String>();
+   
+    public void setSecuredObject(Object object) {
+        Class<?> cls = ClassHelper.getRealClass(object);
+        checkSecureClass(cls);
+        if (scopesMap.isEmpty()) {
+            LOG.warning("The scopes map is empty");
+        } else if (LOG.isLoggable(Level.FINE)) {
+            for (Map.Entry<String, List<String>> entry : scopesMap.entrySet())
{
+                LOG.fine("Method: " + entry.getKey() + ", scopes: " + entry.getValue());
+            }
+        }
+    }
+
+    protected void checkSecureClass(Class<?> cls) {
+        if (cls == null || cls == Object.class) {
+            return;
+        }
+        Scopes classScopes = cls.getAnnotation(Scopes.class);
+        ConfidentialClient classConfClient = cls.getAnnotation(ConfidentialClient.class);
+        for (Method m : cls.getMethods()) {
+            if (SKIP_METHODS.contains(m.getName())) {
+                continue;
+            }
+            Scopes methodScopes = m.getAnnotation(Scopes.class);
+            Scopes theScopes = methodScopes == null ? classScopes : methodScopes;
+            if (theScopes != null) {
+                scopesMap.put(m.getName(), Arrays.asList(theScopes.value()));
+                scopesMatchAllMap.put(m.getName(), theScopes.matchAll());
+            }
+            
+            ConfidentialClient mConfClient = m.getAnnotation(ConfidentialClient.class);
+            if (classConfClient != null || mConfClient != null) {
+                confidentialClientMethods.add(m.getName());
+            }
+        }
+        checkSecureClass(cls.getSuperclass());
+        for (Class<?> interfaceCls : cls.getInterfaces()) {
+            checkSecureClass(interfaceCls);
+        }
+    }
+
+    @Override
+    public void filter(ContainerRequestContext requestContext) throws IOException {
+        Method m = getTargetMethod();
+        checkClient(m);
+        checkScopes(m);
+    }
+    protected void checkClient(Method m) {
+        if (confidentialClientMethods.contains(m.getName())) {
+            OAuthContext context = OAuthContextUtils.getContext(mc);
+            if (!context.isClientConfidential()) {
+                LOG.warning("Non confidential client " + context.getClientId()
+                    + " has attempted to invoke " + m.getName());
+                throw ExceptionUtils.toForbiddenException(null, null);
+            }
+        }
+    }
+    protected void checkScopes(Method m) {
+        List<String> methodScopes = scopesMap.get(m.getName());
+        if (methodScopes == null) {
+            return;
+        }
+        boolean matchAll = scopesMatchAllMap.get(m.getName());
+        OAuthContext context = OAuthContextUtils.getContext(mc);
+        List<String> requestScopes = new LinkedList<String>();
+        for (OAuthPermission perm : context.getPermissions()) {
+            if (matchAll) {
+                requestScopes.add(perm.getPermission());
+            } else if (methodScopes.contains(perm.getPermission())) {
+                return;
+            }
+        }
+        
+        if (!requestScopes.containsAll(methodScopes)) {
+            LOG.warning("Scopes do not match");
+            throw ExceptionUtils.toForbiddenException(null, null);
+        }
+        
+    }
+    protected Method getTargetMethod() {
+        Method method = (Method)mc.get("org.apache.cxf.resource.method");
+        if (method != null) {
+            return method;
+        }
+        throw ExceptionUtils.toForbiddenException(null, null);
+    }
+    
+    
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/64afe084/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/Scopes.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/Scopes.java
b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/Scopes.java
new file mode 100644
index 0000000..8e3eb48
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/Scopes.java
@@ -0,0 +1,44 @@
+/**
+ * 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.cxf.rs.security.oauth2.filters;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Inherited
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+/**
+ * Specifies a list of scopes that a given access token should have in order for
+ * the client invocation to succeed.
+ */
+public @interface Scopes {
+
+    String[] value();
+    
+    /**
+     * If set to true then all the values of this scope have to be matched 
+     */
+    boolean matchAll() default false;
+}


Mime
View raw message