/******************************************************************************* * Copyright (c) 2012 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.cdi.deltaspike.core; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaModelException; import org.jboss.tools.cdi.core.CDICoreNature; import org.jboss.tools.cdi.core.IRootDefinitionContext; import org.jboss.tools.cdi.core.IStereotypeDeclaration; import org.jboss.tools.cdi.core.extension.ICDIExtension; import org.jboss.tools.cdi.core.extension.feature.IBuildParticipantFeature; import org.jboss.tools.cdi.core.extension.feature.IProcessAnnotatedMemberFeature; import org.jboss.tools.cdi.core.extension.feature.IProcessAnnotatedTypeFeature; import org.jboss.tools.cdi.core.extension.feature.IValidatorFeature; import org.jboss.tools.cdi.deltaspike.core.validation.DeltaspikeValidationMessages; import org.jboss.tools.cdi.internal.core.impl.CDIProject; import org.jboss.tools.cdi.internal.core.impl.definition.AbstractMemberDefinition; import org.jboss.tools.cdi.internal.core.impl.definition.AnnotationDefinition; import org.jboss.tools.cdi.internal.core.impl.definition.BeanMemberDefinition; import org.jboss.tools.cdi.internal.core.impl.definition.MethodDefinition; import org.jboss.tools.cdi.internal.core.impl.definition.TypeDefinition; import org.jboss.tools.cdi.internal.core.scanner.FileSet; import org.jboss.tools.cdi.internal.core.validation.CDICoreValidator; import org.jboss.tools.common.java.IAnnotated; import org.jboss.tools.common.java.IAnnotationDeclaration; import org.jboss.tools.common.model.XModelObject; import org.jboss.tools.common.preferences.SeverityPreferences; /** * Runtime * org.apache.deltaspike.security.impl.authorization.SecurityExtension * * @author Viacheslav Kabanovich */ public class DeltaspikeSecurityExtension implements ICDIExtension, IBuildParticipantFeature, IProcessAnnotatedTypeFeature, IProcessAnnotatedMemberFeature, IValidatorFeature, DeltaspikeConstants { public static String ID = "org.apache.deltaspike.security.impl.extension.SecurityExtension"; //$NON-NLS-1$ DeltaspikeSecurityDefinitionContext context = new DeltaspikeSecurityDefinitionContext(); public static DeltaspikeSecurityExtension getExtension(CDICoreNature project) { return (DeltaspikeSecurityExtension)project.getExtensionManager().getExtensionByRuntime(ID); } @Override public DeltaspikeSecurityDefinitionContext getContext() { return context; } @Override public void beginVisiting() {} @Override public void visitJar(IPath path, IPackageFragmentRoot root, XModelObject beansXML) {} @Override public void visit(IFile file, IPath src, IPath webinf) {} @Override public void buildDefinitions() {} @Override public void buildDefinitions(FileSet fileSet) {} @Override public void buildBeans(CDIProject target) {} @Override public void processAnnotatedMember(BeanMemberDefinition memberDefinition, IRootDefinitionContext context) { if(!(memberDefinition instanceof MethodDefinition)) { return; } if(memberDefinition.isAnnotationPresent(SECURES_ANNOTATION_TYPE_NAME)) { MethodDefinition method = (MethodDefinition)memberDefinition; method.setCDIAnnotated(true); DeltaspikeAuthorityMethod authorizer = new DeltaspikeAuthorityMethod(method); DeltaspikeSecurityDefinitionContext contextCopy = ((DeltaspikeSecurityDefinitionContext)this.context.getWorkingCopy()); contextCopy.allAuthorizerMethods.getAuthorizerMembers().add(authorizer); List<SecurityBindingDeclaration> ds = findAnnotationAnnotatedWithSecurityBindingType(memberDefinition, contextCopy.getRootContext()); for (SecurityBindingDeclaration d: ds) { DeltaspikeSecurityBindingConfiguration c = contextCopy.getConfiguration(d.getBinding().getTypeName()); authorizer.addBinding(d, c); c.getAuthorizerMembers().add(authorizer); addToDependencies(c, authorizer.getMethod(), context); } } else { addSecurityMember(memberDefinition, context); } } @Override public void processAnnotatedType(TypeDefinition typeDefinition, IRootDefinitionContext context) { addSecurityMember(typeDefinition, context); } private void addSecurityMember(AbstractMemberDefinition def, IRootDefinitionContext context) { List<SecurityBindingDeclaration> ds = findAnnotationAnnotatedWithSecurityBindingType(def, context); for (SecurityBindingDeclaration d: ds) { addBoundMember(def, d, context); } } private void addBoundMember(AbstractMemberDefinition def, SecurityBindingDeclaration d, IRootDefinitionContext context) { String securityBindingType = d.getBinding().getTypeName(); if(def instanceof MethodDefinition) { ((MethodDefinition)def).setCDIAnnotated(true); } DeltaspikeSecurityBindingConfiguration c = ((DeltaspikeSecurityDefinitionContext)this.context.getWorkingCopy()).getConfiguration(securityBindingType); c.getBoundMembers().put(def, d); addToDependencies(c, def, context); } private void addToDependencies(DeltaspikeSecurityBindingConfiguration c, AbstractMemberDefinition def, IRootDefinitionContext context) { IResource r = def.getResource(); if(r != null && r.exists() && !c.getInvolvedTypes().contains(r.getFullPath())) { IPath newPath = r.getFullPath(); Set<IPath> ps = c.getInvolvedTypes(); for (IPath p: ps) { context.addDependency(p, newPath); context.addDependency(newPath, p); } ps.add(newPath); } } static List<SecurityBindingDeclaration> EMPTY = Collections.<SecurityBindingDeclaration>emptyList(); private List<SecurityBindingDeclaration> findAnnotationAnnotatedWithSecurityBindingType(AbstractMemberDefinition m, IRootDefinitionContext context) { List<SecurityBindingDeclaration> result = null; List<IAnnotationDeclaration> ds = m.getAnnotations(); for (IAnnotationDeclaration d: ds) { if(d instanceof IStereotypeDeclaration) { AnnotationDefinition t = context.getAnnotation(d.getTypeName()); if(t != null) { List<IAnnotationDeclaration> ds1 = findSecurityBindingAnnotations(t, null, context); if(ds1 != null) { if(result == null) { result = new ArrayList<SecurityBindingDeclaration>(); } for (IAnnotationDeclaration d1: ds1) { result.add(new SecurityBindingDeclaration(d, d1)); } } } } else if(d.getTypeName() != null) { AnnotationDefinition a = context.getAnnotation(d.getTypeName()); if(a != null && a.isAnnotationPresent(SECURITY_BINDING_ANNOTATION_TYPE_NAME)) { if(result == null) { result = new ArrayList<SecurityBindingDeclaration>(); } result.add(new SecurityBindingDeclaration(d, d)); } else if(a != null && d instanceof IStereotypeDeclaration) { List<IAnnotationDeclaration> ds1 = findSecurityBindingAnnotations(a, null, context); if(ds1 != null) { if(result == null) { result = new ArrayList<SecurityBindingDeclaration>(); } for (IAnnotationDeclaration d1: ds1) { result.add(new SecurityBindingDeclaration(d, d1)); } } } } } return result == null ? EMPTY : result; } private List<IAnnotationDeclaration> findSecurityBindingAnnotations(IAnnotated s, List<IAnnotationDeclaration> result, IRootDefinitionContext context) { List<IAnnotationDeclaration> ds = s.getAnnotations(); for (IAnnotationDeclaration d: ds) { if(d.getTypeName() != null) { AnnotationDefinition a = context.getAnnotation(d.getTypeName()); if(a != null && a.isAnnotationPresent(SECURITY_BINDING_ANNOTATION_TYPE_NAME)) { if(result == null) { result = new ArrayList<IAnnotationDeclaration>(); } result.add(d); } else if(a != null && d instanceof IStereotypeDeclaration) { List<IAnnotationDeclaration> ds1 = findSecurityBindingAnnotations(a, null, context); if(ds1 != null) { if(result == null) { result = new ArrayList<IAnnotationDeclaration>(); } result.addAll(ds1); } } } } return result; } @Override public void validateResource(IFile file, CDICoreValidator validator) { Set<DeltaspikeAuthorityMethod> authorizers = context.getAuthorityMethods(file.getFullPath()); for (DeltaspikeAuthorityMethod authorizer: authorizers) { IAnnotationDeclaration a = authorizer.getMethod().getAnnotation(SECURES_ANNOTATION_TYPE_NAME); if(authorizer.getBindings().isEmpty()) { validator.addError(DeltaspikeValidationMessages.INVALID_AUTHORIZER_NO_BINDINGS, DeltaspikeSeverityPreferences.INVALID_AUTHORIZER, new String[]{authorizer.getMethod().getMethod().getElementName()}, a, file); } else if(authorizer.getBindings().size() > 1) { validator.addError(DeltaspikeValidationMessages.INVALID_AUTHORIZER_MULTIPLE_BINDINGS, DeltaspikeSeverityPreferences.INVALID_AUTHORIZER, new String[]{authorizer.getMethod().getMethod().getElementName()}, a, file); } try { String returnType = authorizer.getMethod().getMethod().getReturnType(); if(!"Z".equals(returnType)) { //$NON-NLS-1$ validator.addError(DeltaspikeValidationMessages.INVALID_AUTHORIZER_NOT_BOOLEAN, DeltaspikeSeverityPreferences.INVALID_AUTHORIZER, new String[]{authorizer.getMethod().getMethod().getElementName()}, a, file); } } catch (JavaModelException e) { DeltaspikeCorePlugin.getDefault().logError(e); } } Set<DeltaspikeSecurityExtension> parents = null; for (DeltaspikeSecurityBindingConfiguration c: context.getConfigurations().values()) { if(c.getInvolvedTypes().contains(file.getFullPath())) { if(parents == null) { parents = getParents(getContext().getRootContext().getProject()); } Set<DeltaspikeAuthorityMethod> authorizers2 = collectAuthorizerMethods(parents, c.getSecurityBindingTypeName()); authorizers2.addAll(c.getAuthorizerMembers()); Set<String> x = new HashSet<String>(); Iterator<DeltaspikeAuthorityMethod> it = authorizers2.iterator(); while(it.hasNext()) { DeltaspikeAuthorityMethod a = it.next(); String key = a.getKey(); if(x.contains(key)) { it.remove(); } else { x.add(key); } } Map<AbstractMemberDefinition, SecurityBindingDeclaration> bound = c.getBoundMembers(); for (AbstractMemberDefinition d: bound.keySet()) { String name = d instanceof MethodDefinition ? ((MethodDefinition)d).getMethod().getElementName() : d instanceof TypeDefinition ? ((TypeDefinition)d).getQualifiedName() : ""; if(file.getFullPath().equals(d.getTypeDefinition().getType().getPath())) { SecurityBindingDeclaration dc = bound.get(d); int k = 0; for (DeltaspikeAuthorityMethod a: authorizers2) { try { if(a.isMatching(dc.getBinding())) k++; } catch (CoreException e) { DeltaspikeCorePlugin.getDefault().logError(e); } } if(k == 0) { validator.addError(DeltaspikeValidationMessages.UNRESOLVED_AUTHORIZER, DeltaspikeSeverityPreferences.UNRESOLVED_AUTHORIZER, new String[]{dc.getBinding().getTypeName(), name}, dc.getDeclaration(), file); } else if(k > 1) { validator.addError(DeltaspikeValidationMessages.AMBIGUOUS_AUTHORIZER, DeltaspikeSeverityPreferences.AMBIGUOUS_AUTHORIZER, new String[]{dc.getBinding().getTypeName(), name}, dc.getDeclaration(), file); } } } } } // } @Override public SeverityPreferences getSeverityPreferences() { return DeltaspikeSeverityPreferences.getInstance(); } public static Set<DeltaspikeSecurityExtension> getParents(CDICoreNature nature) { Set<CDICoreNature> ps = nature.getCDIProjects(true); Set<DeltaspikeSecurityExtension> parents = new HashSet<DeltaspikeSecurityExtension>(); for (CDICoreNature p: ps) { DeltaspikeSecurityExtension ext = DeltaspikeSecurityExtension.getExtension(p); if(ext != null) parents.add(ext); } return parents; } public static Set<DeltaspikeAuthorityMethod> collectAuthorizerMethods(Set<DeltaspikeSecurityExtension> parents, String securityBindingTypeName) { Set<DeltaspikeAuthorityMethod> result = new HashSet<DeltaspikeAuthorityMethod>(); for (DeltaspikeSecurityExtension ext: parents) { DeltaspikeSecurityBindingConfiguration c = ext.getContext().getConfiguration(securityBindingTypeName); if(c != null) { result.addAll(c.getAuthorizerMembers()); } } return result; } }