Author: sergeyb
Date: Tue Dec  7 22:55:18 2010
New Revision: 1043225

URL: http://svn.apache.org/viewvc?rev=1043225&view=rev
Log:
[CXF-3172] Adding SecureAnnotationsInterceptor

Added:
    
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptor.java
   (with props)
    
cxf/trunk/rt/core/src/test/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptorTest.java
   (with props)
Modified:
    
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/security/AbstractAuthorizingInInterceptor.java

Modified: 
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/security/AbstractAuthorizingInInterceptor.java
URL: 
http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/security/AbstractAuthorizingInInterceptor.java?rev=1043225&r1=1043224&r2=1043225&view=diff
==============================================================================
--- 
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/security/AbstractAuthorizingInInterceptor.java
 (original)
+++ 
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/security/AbstractAuthorizingInInterceptor.java
 Tue Dec  7 22:55:18 2010
@@ -55,11 +55,18 @@ public abstract class AbstractAuthorizin
         throw new AccessDeniedException("Unauthorized");
     }
     
-    private Method getTargetMethod(Message m) {
+    protected Method getTargetMethod(Message m) {
         BindingOperationInfo bop = 
m.getExchange().get(BindingOperationInfo.class);
-        MethodDispatcher md = (MethodDispatcher) 
-            
m.getExchange().get(Service.class).get(MethodDispatcher.class.getName());
-        return md.getMethod(bop);
+        if (bop != null) {
+            MethodDispatcher md = (MethodDispatcher) 
+                
m.getExchange().get(Service.class).get(MethodDispatcher.class.getName());
+            return md.getMethod(bop);
+        } 
+        Method method = (Method)m.get("org.apache.cxf.resource.method");
+        if (method != null) {
+            return method;
+        }
+        throw new AccessDeniedException("Method is not available : 
Unauthorized");
     }
 
     protected boolean authorize(SecurityContext sc, Method method) {

Added: 
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptor.java
URL: 
http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptor.java?rev=1043225&view=auto
==============================================================================
--- 
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptor.java
 (added)
+++ 
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptor.java
 Tue Dec  7 22:55:18 2010
@@ -0,0 +1,97 @@
+/**
+ * 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.interceptor.security;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
+
+
+public class SecureAnnotationsInterceptor extends SimpleAuthorizingInterceptor 
{
+
+    private static final String DEFAULT_ANNOTATION_CLASS_NAME = 
"javax.annotation.security.RolesAllowed";
+    
+    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"}));
+    }
+    
+    private String annotationClassName = DEFAULT_ANNOTATION_CLASS_NAME;
+    
+    public void setAnnotationClassName(String name) {
+        try {
+            ClassLoaderUtils.loadClass(name, 
SecureAnnotationsInterceptor.class);
+            annotationClassName = name;
+        } catch (Throwable ex) {
+            ex.printStackTrace();
+            throw new IllegalArgumentException("Annotation class " + name + " 
is not available");
+        }
+    }
+    
+    public void setSecuredObject(Object object) {
+        Class<?> cls = object.getClass();
+        String classRolesAllowed = getRoles(cls.getAnnotations(), 
annotationClassName);
+        
+        Map<String, String> rolesMap = new HashMap<String, String>();
+        for (Method m : cls.getMethods()) {
+            if (SKIP_METHODS.contains(m.getName())) {
+                continue;
+            }
+            String methodRolesAllowed = getRoles(m.getAnnotations(), 
annotationClassName);
+            String theRoles = methodRolesAllowed != null ? methodRolesAllowed 
: classRolesAllowed;
+            if (theRoles != null) {
+                rolesMap.put(m.getName(), theRoles);
+            }
+        }
+        super.setMethodRolesMap(rolesMap);
+        
+    }
+
+    private String getRoles(Annotation[] anns, String annName) {
+        for (Annotation ann : anns) {
+            if (ann.annotationType().getName().equals(annName)) {
+                try {
+                    Method valueMethod = 
ann.annotationType().getMethod("value", new Class[]{});
+                    String[] roles = (String[])valueMethod.invoke(ann, new 
Object[]{});
+                    StringBuilder sb = new StringBuilder();
+                    for (int i = 0; i < roles.length; i++) {
+                        sb.append(roles[i]);
+                        if (i + 1 < roles.length) {
+                            sb.append(" ");
+                        }
+                    }
+                    return sb.toString();
+                } catch (Exception ex) {
+                    // ignore    
+                }
+                break;
+            }
+        }
+        return null;
+    }
+}

Propchange: 
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptor.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: 
cxf/trunk/rt/core/src/test/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptorTest.java
URL: 
http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/test/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptorTest.java?rev=1043225&view=auto
==============================================================================
--- 
cxf/trunk/rt/core/src/test/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptorTest.java
 (added)
+++ 
cxf/trunk/rt/core/src/test/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptorTest.java
 Tue Dec  7 22:55:18 2010
@@ -0,0 +1,122 @@
+/**
+ * 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.interceptor.security;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import java.lang.reflect.Method;
+import java.security.Principal;
+
+import org.apache.cxf.frontend.MethodDispatcher;
+import org.apache.cxf.message.Exchange;
+import org.apache.cxf.message.ExchangeImpl;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageImpl;
+import org.apache.cxf.security.SecurityContext;
+import org.apache.cxf.service.Service;
+import org.apache.cxf.service.model.BindingOperationInfo;
+import org.easymock.classextension.EasyMock;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class SecureAnnotationsInterceptorTest extends Assert {
+
+    private Method method;
+    private Message message = new MessageImpl();
+    
+    @Before
+    public void setUp() throws Exception {
+        method = TestService.class.getMethod("echo", new Class[]{});
+        message.put(SecurityContext.class, new TestSecurityContext());
+        Exchange ex = new ExchangeImpl();
+        message.setExchange(ex);
+        
+        Service service = EasyMock.createMock(Service.class);
+        ex.put(Service.class, service);
+        MethodDispatcher md = EasyMock.createMock(MethodDispatcher.class);
+        service.get(MethodDispatcher.class.getName());
+        EasyMock.expectLastCall().andReturn(md);
+        
+        BindingOperationInfo boi = 
EasyMock.createMock(BindingOperationInfo.class);
+        ex.put(BindingOperationInfo.class, boi);
+        md.getMethod(boi);
+        EasyMock.expectLastCall().andReturn(method);
+        EasyMock.replay(service, md);
+    }
+    
+    @Test
+    public void testPermitWithNoRoles() {
+        new SecureAnnotationsInterceptor().handleMessage(message);    
+    }
+    
+    @Test
+    public void testPermitWithMethodRoles() {
+        SecureAnnotationsInterceptor in = new SecureAnnotationsInterceptor();
+        in.setAnnotationClassName(SecureRolesAllowed.class.getName());
+        in.setSecuredObject(new TestService());
+        in.handleMessage(message);    
+    }
+    
+    @Test(expected = AccessDeniedException.class)
+    public void testAccessDeniedMethodRoles() {
+        SecureAnnotationsInterceptor in = new SecureAnnotationsInterceptor();
+        in.setAnnotationClassName(SecureRolesAllowed.class.getName());
+        in.setSecuredObject(new TestService2());
+        in.handleMessage(message);    
+    }
+    
+    
+    @Retention (RetentionPolicy.RUNTIME)
+    @Target({ElementType.TYPE, ElementType.METHOD })
+    public @interface SecureRolesAllowed {
+        String[] value();
+    }
+    
+    private static class TestService {
+        @SuppressWarnings("unused")
+        @SecureRolesAllowed("testRole")
+        public void echo() {
+        }
+    }
+    
+    private static class TestService2 {
+        @SuppressWarnings("unused")
+        @SecureRolesAllowed("baz")
+        public void echo() {
+        }
+    }
+    
+    private static class TestSecurityContext implements SecurityContext {
+
+        public Principal getUserPrincipal() {
+            return null;
+        }
+
+        public boolean isUserInRole(String role) {
+            return "testRole".equals(role);
+        }
+        
+    }
+}

Propchange: 
cxf/trunk/rt/core/src/test/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
cxf/trunk/rt/core/src/test/java/org/apache/cxf/interceptor/security/SecureAnnotationsInterceptorTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date


Reply via email to