From 947748848e25c84d82a14906a8b76533dcfd2087 Mon Sep 17 00:00:00 2001 From: aboyko Date: Fri, 24 Feb 2023 15:07:28 -0500 Subject: [PATCH] Marker and quick fix for the old API HttpSecurity.authorizeRequests(...) --- .../boot/java/Boot2JavaProblemType.java | 4 +- .../rewrite/BootCodeActionRepository.java | 4 +- .../AuthorizeHttpRequestsCodeAction.java | 128 ++++++++++++++++++ 3 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/reconcile/AuthorizeHttpRequestsCodeAction.java diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Boot2JavaProblemType.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Boot2JavaProblemType.java index ea7771c49..2a50d5d17 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Boot2JavaProblemType.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Boot2JavaProblemType.java @@ -36,7 +36,9 @@ public enum Boot2JavaProblemType implements ProblemType { JAVA_LAMBDA_DSL(INFO, "Consider switching to Lambda DSL syntax", "Switch to Lambda DSL syntax"), - MISSING_CONFIGURATION_ANNOTATION(WARNING, "Class likely missing '@Configuration' annotation, i.e. has Bean methods but no '@Configuration' annotation", "Missing '@Configuration'"); + 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"); private final ProblemSeverity defaultSeverity; private String description; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/BootCodeActionRepository.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/BootCodeActionRepository.java index 30e449b78..838af83a1 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/BootCodeActionRepository.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/BootCodeActionRepository.java @@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.java.rewrite; import java.util.List; import org.springframework.ide.vscode.boot.java.rewrite.reconcile.AddConfigurationIfBeansPresentCodeAction; +import org.springframework.ide.vscode.boot.java.rewrite.reconcile.AuthorizeHttpRequestsCodeAction; import org.springframework.ide.vscode.boot.java.rewrite.reconcile.AutowiredFieldIntoConstructorParameterCodeAction; import org.springframework.ide.vscode.boot.java.rewrite.reconcile.BeanMethodNotPublicProblem; import org.springframework.ide.vscode.boot.java.rewrite.reconcile.BeanPostProcessingIgnoreInAotProblem; @@ -45,7 +46,8 @@ public class BootCodeActionRepository extends CodeActionRepository { new NoRepoAnnotationProblem(), new HttpSecurityLamdaDslCodeAction(), new ServerHttpSecurityLambdaDslCodeAction(), - new AddConfigurationIfBeansPresentCodeAction() + new AddConfigurationIfBeansPresentCodeAction(), + new AuthorizeHttpRequestsCodeAction() ); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/reconcile/AuthorizeHttpRequestsCodeAction.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/reconcile/AuthorizeHttpRequestsCodeAction.java new file mode 100644 index 000000000..823c10bee --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/reconcile/AuthorizeHttpRequestsCodeAction.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * 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.MethodMatcher; +import org.openrewrite.java.tree.J.MethodInvocation; +import org.openrewrite.java.tree.J.VariableDeclarations; +import org.openrewrite.java.tree.JavaType.FullyQualified; +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 AuthorizeHttpRequestsCodeAction implements RecipeCodeActionDescriptor { + + private static final String ID = "org.openrewrite.java.spring.boot2.AuthorizeHttpRequests"; + + private static final MethodMatcher MATCH_AUTHORIZE_REQUESTS = new MethodMatcher( + "org.springframework.security.config.annotation.web.builders.HttpSecurity authorizeRequests(..)"); + + private static final String AUTHORIZE_REQUESTS_PROBLEM_LABEL = "HttpSecurity API 'authorizeRequests(...)' is outdated"; + + private static final String AUTHORIZE_REQUESTS_FIX_LABEL = "Replace with 'authorizeHttpRequests(...)' and related types"; + + private static final String CLASS_FIX_LABEL_TEMPLATE = "Replace with %s and use 'HttpSecurity.authorizeHttpRequests(...) and related types"; + + @Override + public String getId() { + return ID; + } + + @Override + public ProblemType getProblemType() { + return Boot2JavaProblemType.HTTP_SECIRITY_AUTHORIZE_HTTP_REQUESTS; + } + + @Override + public JavaVisitor getMarkerVisitor(ApplicationContext applicationContext) { + return new JavaMarkerVisitor<>() { + + @Override + public MethodInvocation visitMethodInvocation(MethodInvocation method, ExecutionContext p) { + MethodInvocation m = super.visitMethodInvocation(method, p); + if (MATCH_AUTHORIZE_REQUESTS.matches(method)) { + String uri = getCursor().firstEnclosing(SourceFile.class).getSourcePath().toUri().toASCIIString(); + FixAssistMarker marker = new FixAssistMarker(Tree.randomId(), getId()) + .withLabel(AUTHORIZE_REQUESTS_PROBLEM_LABEL).withFixes( + new FixDescriptor(ID, List.of(uri), + RecipeCodeActionDescriptor.buildLabel(AUTHORIZE_REQUESTS_FIX_LABEL, + RecipeScope.FILE)) + .withRecipeScope(RecipeScope.FILE), + new FixDescriptor(ID, List.of(uri), RecipeCodeActionDescriptor + .buildLabel(AUTHORIZE_REQUESTS_FIX_LABEL, RecipeScope.PROJECT)) + .withRecipeScope(RecipeScope.PROJECT)); + m = m.withName(m.getName().withMarkers(m.getName().getMarkers().add(marker))); + } + return m; + } + + @Override + public VariableDeclarations visitVariableDeclarations(VariableDeclarations multiVariable, + ExecutionContext p) { + VariableDeclarations mv = super.visitVariableDeclarations(multiVariable, p); + FullyQualified type = mv.getTypeAsFullyQualified(); + if (type != null) { + String replacementClass = null; + switch (type.getFullyQualifiedName()) { + case "org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer": + case "org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer": + replacementClass = "AuthorizeHttpRequestsConfigurer"; + break; + case "org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer$ExpressionInterceptUrlRegistry": + replacementClass = "AuthorizationManagerRequestMatcherRegistry"; + } + if (replacementClass != null) { + String uri = getCursor().firstEnclosing(SourceFile.class).getSourcePath().toUri() + .toASCIIString(); + FixAssistMarker marker = new FixAssistMarker(Tree.randomId(), getId()) + .withLabel("Use of type '" + type.getClassName() + "' is outdated").withFixes( + new FixDescriptor(ID, List.of(uri), + RecipeCodeActionDescriptor.buildLabel( + String.format(CLASS_FIX_LABEL_TEMPLATE, replacementClass), + RecipeScope.FILE)) + .withRecipeScope(RecipeScope.FILE), + new FixDescriptor(ID, List.of(uri), + RecipeCodeActionDescriptor.buildLabel( + String.format(CLASS_FIX_LABEL_TEMPLATE, replacementClass), + RecipeScope.PROJECT)) + .withRecipeScope(RecipeScope.PROJECT)); + + mv = mv.withTypeExpression( + mv.getTypeExpression().withMarkers(mv.getTypeExpression().getMarkers().add(marker))); + } + } + return mv; + } + + }; + } + + @Override + public boolean isApplicable(IJavaProject project) { + Version version = SpringProjectUtil.getDependencyVersion(project, "spring-security-config"); + return version != null && version.compareTo(new Version(5, 6, 0, null)) >= 0; + } + +}