WebSecurityConfigurerAdapter quick fix for Security 6.0.x code
This commit is contained in:
@@ -38,7 +38,7 @@ public class RewriteConfig {
|
||||
|
||||
@ConditionalOnBean(RewriteRecipeRepository.class)
|
||||
@Bean RewriteRefactorings rewriteRefactorings(SimpleLanguageServer server, JavaProjectFinder projectFinder, RewriteRecipeRepository recipeRepo, RewriteCompilationUnitCache cuCache) {
|
||||
return new RewriteRefactorings(server.getTextDocumentService(), projectFinder, recipeRepo, cuCache);
|
||||
return new RewriteRefactorings(server, projectFinder, recipeRepo, cuCache);
|
||||
}
|
||||
|
||||
@ConditionalOnBean(RewriteRecipeRepository.class)
|
||||
|
||||
@@ -12,10 +12,13 @@ package org.springframework.ide.vscode.boot.java.rewrite;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.lsp4j.CodeAction;
|
||||
@@ -24,22 +27,25 @@ import org.eclipse.lsp4j.TextDocumentEdit;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.WorkspaceEdit;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.openrewrite.Parser.Input;
|
||||
import org.openrewrite.Recipe;
|
||||
import org.openrewrite.RecipeRun;
|
||||
import org.openrewrite.Result;
|
||||
import org.openrewrite.config.DeclarativeRecipe;
|
||||
import org.openrewrite.internal.RecipeIntrospectionUtils;
|
||||
import org.openrewrite.java.JavaParser;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.J.CompilationUnit;
|
||||
import org.openrewrite.marker.Range;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.PercentageProgressTask;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixEdit;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.CodeActionResolver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.rewrite.ORDocUtils;
|
||||
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
|
||||
@@ -60,7 +66,7 @@ public class RewriteRefactorings implements CodeActionResolver, QuickfixHandler
|
||||
|
||||
private RewriteRecipeRepository recipeRepo;
|
||||
|
||||
private SimpleTextDocumentService documents;
|
||||
private SimpleLanguageServer server;
|
||||
|
||||
private RewriteCompilationUnitCache cuCache;
|
||||
|
||||
@@ -68,8 +74,8 @@ public class RewriteRefactorings implements CodeActionResolver, QuickfixHandler
|
||||
|
||||
private Gson gson;
|
||||
|
||||
public RewriteRefactorings(SimpleTextDocumentService documents, JavaProjectFinder projectFinder, RewriteRecipeRepository recipeRepo, RewriteCompilationUnitCache cuCache) {
|
||||
this.documents = documents;
|
||||
public RewriteRefactorings(SimpleLanguageServer server, JavaProjectFinder projectFinder, RewriteRecipeRepository recipeRepo, RewriteCompilationUnitCache cuCache) {
|
||||
this.server = server;
|
||||
this.projectFinder = projectFinder;
|
||||
this.recipeRepo = recipeRepo;
|
||||
this.cuCache = cuCache;
|
||||
@@ -120,7 +126,7 @@ public class RewriteRefactorings implements CodeActionResolver, QuickfixHandler
|
||||
List<Result> results = reciperun.getResults();
|
||||
List<Either<TextDocumentEdit, ResourceOperation>> edits = results.stream().filter(res -> res.getAfter() != null).map(res -> {
|
||||
URI docUri = res.getAfter().getSourcePath().isAbsolute() ? res.getAfter().getSourcePath().toUri() : project.getLocationUri().resolve(res.getAfter().getSourcePath().toString());
|
||||
TextDocument doc = documents.getLatestSnapshot(docUri.toASCIIString());
|
||||
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(docUri.toASCIIString());
|
||||
if (doc == null) {
|
||||
doc = new TextDocument(docUri.toASCIIString(), LanguageId.JAVA, 0, res.getBefore() == null ? "" : res.getBefore().printAll());
|
||||
}
|
||||
@@ -138,12 +144,27 @@ public class RewriteRefactorings implements CodeActionResolver, QuickfixHandler
|
||||
Optional<IJavaProject> project = projectFinder.find(new TextDocumentIdentifier(data.getDocUris().get(0)));
|
||||
if (project.isPresent()) {
|
||||
boolean projectWide = data.getRecipeScope() == RecipeScope.PROJECT;
|
||||
Recipe r = createRecipe(data);
|
||||
Recipe r = createRecipe(data);
|
||||
List<CompilationUnit> cus = Collections.emptyList();
|
||||
if (projectWide) {
|
||||
//TODO: progress here as well.
|
||||
return applyRecipe(r, project.get(), ORAstUtils.parse(documents, project.get(), null));
|
||||
JavaParser jp = ORAstUtils.createJavaParserBuilder(project.get()).dependsOn(data.getTypeStubs()).build();
|
||||
List<Input> inputs = ORAstUtils.getParserInputs(server.getTextDocumentService(), project.get());
|
||||
PercentageProgressTask progress = server.getProgressService().createPercentageProgressTask(UUID.randomUUID().toString(), inputs.size() + 1, data.getLabel());
|
||||
try {
|
||||
cus = ORAstUtils.parseInputs(jp, inputs, s -> progress.increment());
|
||||
return applyRecipe(r, project.get(), cus);
|
||||
} finally {
|
||||
progress.setCurrent(progress.getTotal());
|
||||
progress.done();
|
||||
}
|
||||
} else {
|
||||
List<CompilationUnit> cus = data.getDocUris().stream().map(docUri -> cuCache.getCU(project.get(), URI.create(docUri))).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (data.getTypeStubs().length == 0) {
|
||||
cus = data.getDocUris().stream().map(docUri -> cuCache.getCU(project.get(), URI.create(docUri))).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
} else {
|
||||
JavaParser jp = ORAstUtils.createJavaParserBuilder(project.get()).dependsOn(data.getTypeStubs()).build();
|
||||
List<Input> inputs = data.getDocUris().stream().map(URI::create).map(Paths::get).map(p -> ORAstUtils.getParserInput(server.getTextDocumentService(), p)).collect(Collectors.toList());
|
||||
cus = ORAstUtils.parseInputs(jp, inputs, null);
|
||||
}
|
||||
return applyRecipe(r, project.get(), cus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,33 @@ public class WebSecurityConfigurerAdapterCodeAction implements RecipeCodeActionD
|
||||
|
||||
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'";
|
||||
private static final String FIX_LABEL = "Refactor class into a Configuration bean not extending 'WebSecurityConfigurerAdapter'";
|
||||
|
||||
private static final String STUB_WEB_SECURITY_CONFIG_ADAPTER = """
|
||||
package org.springframework.security.config.annotation.web.configuration;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
public abstract class WebSecurityConfigurerAdapter {
|
||||
|
||||
public void init(WebSecurity web) throws Exception {}
|
||||
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception { return null; }
|
||||
|
||||
public UserDetailsService userDetailsServiceBean() throws Exception { return null; }
|
||||
|
||||
protected void configure(HttpSecurity http) throws Exception {}
|
||||
|
||||
public void configure(WebSecurity web) throws Exception {}
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {}
|
||||
}
|
||||
""";
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
@@ -62,48 +88,52 @@ public class WebSecurityConfigurerAdapterCodeAction implements RecipeCodeActionD
|
||||
@Override
|
||||
public ClassDeclaration visitClassDeclaration(ClassDeclaration classDecl, ExecutionContext p) {
|
||||
ClassDeclaration c = super.visitClassDeclaration(classDecl, p);
|
||||
if (isExtendingWebSecurityConfigurerAdapter(c)) {
|
||||
TypeTree superClass = c.getExtends();
|
||||
boolean isExtendingWebSecurityConfigurerAdapter = false;
|
||||
boolean isUnresolved = false;
|
||||
if (superClass != null) {
|
||||
if (superClass.getType() instanceof JavaType.Unknown) {
|
||||
String strType = superClass.printTrimmed(getCursor());
|
||||
isExtendingWebSecurityConfigurerAdapter = "WebSecurityConfigurerAdapter".equals(strType) || FQN_WEB_SECURITY_CONFIGURER_ADAPTER.equals(strType);
|
||||
isUnresolved = true;
|
||||
} else if (superClass.getType() instanceof JavaType.FullyQualified) {
|
||||
isExtendingWebSecurityConfigurerAdapter = FQN_WEB_SECURITY_CONFIGURER_ADAPTER.equals( ((JavaType.FullyQualified)superClass.getType()).getFullyQualifiedName());
|
||||
}
|
||||
}
|
||||
if (isExtendingWebSecurityConfigurerAdapter) {
|
||||
if (isAnnotatedWith(c.getLeadingAnnotations(), Annotations.CONFIGURATION)) {
|
||||
String uri = getCursor().firstEnclosing(SourceFile.class).getSourcePath().toUri().toASCIIString();
|
||||
String[] typeStubs = new String[0];
|
||||
if (isUnresolved) {
|
||||
typeStubs = new String[] { STUB_WEB_SECURITY_CONFIG_ADAPTER };
|
||||
}
|
||||
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),
|
||||
.withRecipeScope(RecipeScope.FILE)
|
||||
.withTypeStubs(typeStubs),
|
||||
new FixDescriptor(ID, List.of(uri),
|
||||
RecipeCodeActionDescriptor.buildLabel(FIX_LABEL, RecipeScope.PROJECT))
|
||||
.withRecipeScope(RecipeScope.PROJECT));
|
||||
.withRecipeScope(RecipeScope.PROJECT)
|
||||
.withTypeStubs(typeStubs));
|
||||
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;
|
||||
return version != null && version.compareTo(new Version(5, 7, 0, null)) >= 0 && version.compareTo(new Version(6, 1, 0, null)) < 0;
|
||||
}
|
||||
|
||||
private static boolean isAnnotatedWith(Collection<J.Annotation> annotations, String annotationType) {
|
||||
return annotations.stream().anyMatch(a -> TypeUtils.isOfClassType(a.getType(), annotationType));
|
||||
}
|
||||
|
||||
private static boolean isAnnotatedWith(Collection<J.Annotation> annotations, String annotationType) {
|
||||
return annotations.stream().anyMatch(a -> TypeUtils.isOfClassType(a.getType(), annotationType));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user