Return-Path: Delivered-To: apmail-cxf-commits-archive@www.apache.org Received: (qmail 49169 invoked from network); 7 Dec 2010 22:55:44 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 7 Dec 2010 22:55:44 -0000 Received: (qmail 31501 invoked by uid 500); 7 Dec 2010 22:55:44 -0000 Delivered-To: apmail-cxf-commits-archive@cxf.apache.org Received: (qmail 31451 invoked by uid 500); 7 Dec 2010 22:55:44 -0000 Mailing-List: contact commits-help@cxf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cxf.apache.org Delivered-To: mailing list commits@cxf.apache.org Received: (qmail 31444 invoked by uid 99); 7 Dec 2010 22:55:44 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 07 Dec 2010 22:55:44 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 07 Dec 2010 22:55:40 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id C71902388A39; Tue, 7 Dec 2010 22:55:18 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1043225 - in /cxf/trunk/rt/core/src: main/java/org/apache/cxf/interceptor/security/ test/java/org/apache/cxf/interceptor/security/ Date: Tue, 07 Dec 2010 22:55:18 -0000 To: commits@cxf.apache.org From: sergeyb@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20101207225518.C71902388A39@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 SKIP_METHODS; + static { + SKIP_METHODS = new HashSet(); + 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 rolesMap = new HashMap(); + 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