Marker and quick fix for WebSecurityConfigurerAdapter
This commit is contained in:
@@ -1,142 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.rewrite.java;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.openrewrite.Cursor;
|
||||
import org.openrewrite.ExecutionContext;
|
||||
import org.openrewrite.Recipe;
|
||||
import org.openrewrite.TreeVisitor;
|
||||
import org.openrewrite.java.AnnotationMatcher;
|
||||
import org.openrewrite.java.JavaIsoVisitor;
|
||||
import org.openrewrite.java.JavaParser;
|
||||
import org.openrewrite.java.JavaTemplate;
|
||||
import org.openrewrite.java.search.UsesType;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.JavaType;
|
||||
import org.openrewrite.java.tree.Statement;
|
||||
import org.openrewrite.java.tree.TypeUtils;
|
||||
|
||||
public class AddConfigurationAnnotationIfBeansPresent extends Recipe {
|
||||
|
||||
private static final String CONFIGURATION_PACKAGE = "org.springframework.context.annotation";
|
||||
|
||||
private static final String CONFIGURATION_SIMPLE_NAME = "Configuration";
|
||||
|
||||
private static final String FQN_CONFIGURATION = CONFIGURATION_PACKAGE + "." + CONFIGURATION_SIMPLE_NAME;
|
||||
|
||||
private static final String FQN_BEAN = "org.springframework.context.annotation.Bean";
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Add missing '@Configuration' annotation";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Class having `@Bean' annotation over any methods but missing '@Configuration' annotation over the declaring class would have '@Configuration' annotation added.";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TreeVisitor<?, ExecutionContext> getApplicableTest() {
|
||||
return new UsesType<>(FQN_BEAN);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TreeVisitor<?, ExecutionContext> getVisitor() {
|
||||
return new JavaIsoVisitor<ExecutionContext>() {
|
||||
|
||||
@Override
|
||||
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext p) {
|
||||
J.ClassDeclaration c = super.visitClassDeclaration(classDecl, p);
|
||||
if (isApplicableClass(c, getCursor())) {
|
||||
c = addConfigurationAnnotation(c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private J.ClassDeclaration addConfigurationAnnotation(J.ClassDeclaration c) {
|
||||
maybeAddImport(FQN_CONFIGURATION);
|
||||
JavaTemplate template = JavaTemplate.builder(() -> getCursor(), "@" + CONFIGURATION_SIMPLE_NAME)
|
||||
.imports(
|
||||
FQN_CONFIGURATION)
|
||||
.javaParser(() -> JavaParser.fromJavaVersion().dependsOn("package " + CONFIGURATION_PACKAGE
|
||||
+ "; public @interface " + CONFIGURATION_SIMPLE_NAME + " {}").build())
|
||||
.build();
|
||||
return c.withTemplate(template,
|
||||
c.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName)));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean isApplicableClass(J.ClassDeclaration classDecl, Cursor cursor) {
|
||||
if (classDecl.getKind() == J.ClassDeclaration.Kind.Type.Class) {
|
||||
boolean isStatic = false;
|
||||
for (J.Modifier m : classDecl.getModifiers()) {
|
||||
if (m.getType() == J.Modifier.Type.Abstract) {
|
||||
return false;
|
||||
} else if (m.getType() == J.Modifier.Type.Static) {
|
||||
isStatic = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isStatic) {
|
||||
// no static keyword? check if it is top level class in the CU
|
||||
J.CompilationUnit cu = cursor.dropParentUntil(J.CompilationUnit.class::isInstance).getValue();
|
||||
if (!cu.getClasses().contains(classDecl)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check if '@Configuration' is already over the class
|
||||
AnnotationMatcher matcher = new AnnotationMatcher("@" + FQN_CONFIGURATION, true);
|
||||
|
||||
for (J.Annotation a : classDecl.getLeadingAnnotations()) {
|
||||
JavaType.FullyQualified aType = TypeUtils.asFullyQualified(a.getType());
|
||||
if (aType != null && matcher.matchesAnnotationOrMetaAnnotation(aType)) {
|
||||
// Found '@Configuration' annotation
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// No '@Configuration' present. Check if any methods have '@Bean' annotation
|
||||
for (Statement s : classDecl.getBody().getStatements()) {
|
||||
if (s instanceof J.MethodDeclaration) {
|
||||
if (isBeanMethod((J.MethodDeclaration) s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isBeanMethod(J.MethodDeclaration methodDecl) {
|
||||
for (J.Modifier m : methodDecl.getModifiers()) {
|
||||
if (m.getType() == J.Modifier.Type.Abstract) {
|
||||
return false;
|
||||
} else if (m.getType() == J.Modifier.Type.Static) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
AnnotationMatcher beanAnnotationMatcher = new AnnotationMatcher("@" + FQN_BEAN, true);
|
||||
for (J.Annotation a : methodDecl.getLeadingAnnotations()) {
|
||||
JavaType.FullyQualified aType = TypeUtils.asFullyQualified(a.getType());
|
||||
if (aType != null && beanAnnotationMatcher.matchesAnnotationOrMetaAnnotation(aType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -38,7 +38,9 @@ public enum Boot2JavaProblemType implements ProblemType {
|
||||
|
||||
MISSING_CONFIGURATION_ANNOTATION(WARNING, "Class likely missing '@Configuration' annotation, i.e. has Bean methods but no '@Configuration' annotation", "Missing '@Configuration'"),
|
||||
|
||||
HTTP_SECIRITY_AUTHORIZE_HTTP_REQUESTS(WARNING, "'HttpSecurity.authroizeRequests(...)' API and related classes are to be deprecated use new `authorizeHttpRequests(...) and related classes", "Usage of old 'HttpSecurity.authroizeRequests(...)' API");
|
||||
HTTP_SECIRITY_AUTHORIZE_HTTP_REQUESTS(WARNING, "'HttpSecurity.authroizeRequests(...)' API and related classes are to be deprecated use new `authorizeHttpRequests(...) and related classes", "Usage of old 'HttpSecurity.authroizeRequests(...)' API"),
|
||||
|
||||
WEB_SECURITY_CONFIGURER_ADAPTER(WARNING, "'WebSecurityConfigurerAdapter' is removed in Spring-Security 6.x. Refactor classes extending the 'WebSecurityConfigurerAdapter' into 'Configuration' beans and methods into 'Bean' definitions ", "Replace usage of 'WebSecurityConfigurerAdapter' as this class to be removed in Security 6.x");
|
||||
|
||||
private final ProblemSeverity defaultSeverity;
|
||||
private String description;
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.ide.vscode.boot.java.rewrite.reconcile.NotRegisteredB
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.reconcile.PreciseBeanTypeProblem;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.reconcile.ServerHttpSecurityLambdaDslCodeAction;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.reconcile.UnnecessarySpringExtensionProblem;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.reconcile.WebSecurityConfigurerAdapterCodeAction;
|
||||
import org.springframework.ide.vscode.commons.rewrite.config.CodeActionRepository;
|
||||
import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDescriptor;
|
||||
|
||||
@@ -47,7 +48,8 @@ public class BootCodeActionRepository extends CodeActionRepository {
|
||||
new HttpSecurityLamdaDslCodeAction(),
|
||||
new ServerHttpSecurityLambdaDslCodeAction(),
|
||||
new AddConfigurationIfBeansPresentCodeAction(),
|
||||
new AuthorizeHttpRequestsCodeAction()
|
||||
new AuthorizeHttpRequestsCodeAction(),
|
||||
new WebSecurityConfigurerAdapterCodeAction()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.openrewrite.ExecutionContext;
|
||||
import org.openrewrite.SourceFile;
|
||||
import org.openrewrite.Tree;
|
||||
import org.openrewrite.java.JavaVisitor;
|
||||
import org.openrewrite.java.spring.boot2.AddConfigurationAnnotationIfBeansPresent;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.J.VariableDeclarations;
|
||||
@@ -27,14 +28,13 @@ import org.springframework.ide.vscode.commons.java.Version;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
|
||||
import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDescriptor;
|
||||
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.AddConfigurationAnnotationIfBeansPresent;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.JavaMarkerVisitor;
|
||||
|
||||
public class AddConfigurationIfBeansPresentCodeAction implements RecipeCodeActionDescriptor {
|
||||
|
||||
private static final String ID = "org.springframework.ide.vscode.commons.rewrite.java.AddConfigurationAnnotationIfBeansPresent";
|
||||
private static final String ID = "org.openrewrite.java.spring.boot2.AddConfigurationAnnotationIfBeansPresent";
|
||||
|
||||
private static final String PROBLEM_LABEL = "'@Configuration' is missing on a class defining Spring Beans";
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.rewrite.reconcile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.openrewrite.ExecutionContext;
|
||||
import org.openrewrite.SourceFile;
|
||||
import org.openrewrite.Tree;
|
||||
import org.openrewrite.java.JavaVisitor;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.JavaType;
|
||||
import org.openrewrite.java.tree.TypeTree;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.java.Version;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
|
||||
import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDescriptor;
|
||||
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.JavaMarkerVisitor;
|
||||
|
||||
public class WebSecurityConfigurerAdapterCodeAction implements RecipeCodeActionDescriptor {
|
||||
|
||||
private static final String ID = "org.openrewrite.java.spring.boot2.WebSecurityConfigurerAdapter";
|
||||
|
||||
private static final String FQN_WEB_SECURITY_CONFIGURER_ADAPTER = "org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter";
|
||||
|
||||
private static final String PROBLEM_LABEL = "Class extends 'WebSecurityConfigurerAdapter' which is removed in Spring-Security 6.x";
|
||||
|
||||
protected static final String FIX_LABEL = "Refactor class into a Configuration bean not extending 'WebSecurityConfigurerAdapter'";
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProblemType getProblemType() {
|
||||
return Boot2JavaProblemType.WEB_SECURITY_CONFIGURER_ADAPTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
|
||||
return new JavaMarkerVisitor<>() {
|
||||
|
||||
@Override
|
||||
public ClassDeclaration visitClassDeclaration(ClassDeclaration classDecl, ExecutionContext p) {
|
||||
ClassDeclaration c = super.visitClassDeclaration(classDecl, p);
|
||||
if (isExtendingWebSecurityConfigurerAdapter(c)) {
|
||||
String uri = getCursor().firstEnclosing(SourceFile.class).getSourcePath().toUri().toASCIIString();
|
||||
FixAssistMarker marker = new FixAssistMarker(Tree.randomId(), ID).withLabel(PROBLEM_LABEL)
|
||||
.withFixes(
|
||||
new FixDescriptor(ID, List.of(uri),
|
||||
RecipeCodeActionDescriptor.buildLabel(FIX_LABEL, RecipeScope.FILE))
|
||||
.withRecipeScope(RecipeScope.FILE),
|
||||
new FixDescriptor(ID, List.of(uri),
|
||||
RecipeCodeActionDescriptor.buildLabel(FIX_LABEL, RecipeScope.PROJECT))
|
||||
.withRecipeScope(RecipeScope.PROJECT));
|
||||
c = c.withName(c.getName().withMarkers(c.getName().getMarkers().add(marker)));
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private boolean isExtendingWebSecurityConfigurerAdapter(J.ClassDeclaration c) {
|
||||
TypeTree superClass = c.getExtends();
|
||||
if (superClass != null) {
|
||||
if (superClass.getType() instanceof JavaType.FullyQualified) {
|
||||
return FQN_WEB_SECURITY_CONFIGURER_ADAPTER.equals( ((JavaType.FullyQualified)superClass.getType()).getFullyQualifiedName());
|
||||
} else if (superClass.getType() instanceof JavaType.Unknown) {
|
||||
String strType = superClass.printTrimmed(getCursor());
|
||||
return "WebSecurityConfigurerAdapter".equals(strType) || FQN_WEB_SECURITY_CONFIGURER_ADAPTER.equals(strType);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(IJavaProject project) {
|
||||
Version version = SpringProjectUtil.getDependencyVersion(project, "spring-security-config");
|
||||
return version != null && version.compareTo(new Version(5, 7, 0, null)) >= 0 && version.compareTo(new Version(6, 0, 0, null)) < 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -61,6 +61,18 @@
|
||||
"label": "Missing '@Configuration'",
|
||||
"description": "Class likely missing '@Configuration' annotation, i.e. has Bean methods but no '@Configuration' annotation",
|
||||
"defaultSeverity": "WARNING"
|
||||
},
|
||||
{
|
||||
"code": "HTTP_SECIRITY_AUTHORIZE_HTTP_REQUESTS",
|
||||
"label": "Usage of old 'HttpSecurity.authroizeRequests(...)' API",
|
||||
"description": "'HttpSecurity.authroizeRequests(...)' API and related classes are to be deprecated use new `authorizeHttpRequests(...) and related classes",
|
||||
"defaultSeverity": "WARNING"
|
||||
},
|
||||
{
|
||||
"code": "WEB_SECURITY_CONFIGURER_ADAPTER",
|
||||
"label": "Replace usage of 'WebSecurityConfigurerAdapter' as this class to be removed in Security 6.x",
|
||||
"description": "'WebSecurityConfigurerAdapter' is removed in Spring-Security 6.x. Refactor classes extending the 'WebSecurityConfigurerAdapter' into 'Configuration' beans and methods into 'Bean' definitions ",
|
||||
"defaultSeverity": "WARNING"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -426,6 +426,30 @@
|
||||
"HINT",
|
||||
"ERROR"
|
||||
]
|
||||
},
|
||||
"spring-boot.ls.problem.boot2.HTTP_SECIRITY_AUTHORIZE_HTTP_REQUESTS": {
|
||||
"type": "string",
|
||||
"default": "WARNING",
|
||||
"description": "'HttpSecurity.authroizeRequests(...)' API and related classes are to be deprecated use new `authorizeHttpRequests(...) and related classes",
|
||||
"enum": [
|
||||
"IGNORE",
|
||||
"INFO",
|
||||
"WARNING",
|
||||
"HINT",
|
||||
"ERROR"
|
||||
]
|
||||
},
|
||||
"spring-boot.ls.problem.boot2.WEB_SECURITY_CONFIGURER_ADAPTER": {
|
||||
"type": "string",
|
||||
"default": "WARNING",
|
||||
"description": "'WebSecurityConfigurerAdapter' is removed in Spring-Security 6.x. Refactor classes extending the 'WebSecurityConfigurerAdapter' into 'Configuration' beans and methods into 'Bean' definitions ",
|
||||
"enum": [
|
||||
"IGNORE",
|
||||
"INFO",
|
||||
"WARNING",
|
||||
"HINT",
|
||||
"ERROR"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user