44import java .util .Collections ;
55import java .util .List ;
66import java .util .UUID ;
7+ import java .util .stream .Collectors ;
78import org .openrewrite .ExecutionContext ;
89import org .openrewrite .Recipe ;
910import org .openrewrite .TreeVisitor ;
1011import org .openrewrite .java .ChangeMethodName ;
1112import org .openrewrite .java .ChangePackage ;
1213import org .openrewrite .java .ChangeType ;
1314import org .openrewrite .java .JavaIsoVisitor ;
15+ import org .openrewrite .java .MethodMatcher ;
16+ import org .openrewrite .java .tree .Expression ;
1417import org .openrewrite .java .tree .J ;
18+ import org .openrewrite .java .tree .JContainer ;
1519import org .openrewrite .java .tree .JLeftPadded ;
20+ import org .openrewrite .java .tree .JRightPadded ;
21+ import org .openrewrite .java .tree .JavaType ;
1622import org .openrewrite .java .tree .Space ;
1723import org .openrewrite .marker .Markers ;
1824import org .slf4j .Logger ;
@@ -42,26 +48,40 @@ public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionCon
4248 // ChangePackage will take care for the most of the migration so don't need to add separate migrations
4349 // For those import statements that ChangePackage will not account correctly, add separate logic
4450 cu = (J .CompilationUnit )
45- new ChangePackage ("org.acegisecurity" , "org.springframework.security.core" , false )
51+ new ChangePackage ("org.acegisecurity" , "org.springframework.security.core" , true )
4652 .getVisitor ()
4753 .visitNonNull (cu , ctx );
4854
55+ List <J .Import > originalImports = cu .getImports ();
56+
4957 cu = (J .CompilationUnit ) new ChangeType (
5058 "org.springframework.security.core.GrantedAuthorityImpl" ,
5159 "org.springframework.security.core.authority.SimpleGrantedAuthority" ,
5260 null )
5361 .getVisitor ()
5462 .visitNonNull (cu , ctx );
5563
64+ if (!cu .getImports ().equals (originalImports )) {
65+ cu = addImportIfNotExists (
66+ cu , "SimpleGrantedAuthority" , "org.springframework.security.core.authority" );
67+ }
68+ originalImports = cu .getImports ();
69+
5670 // Authentication classes
5771 cu = (J .CompilationUnit ) new ChangeType (
58- "org.acegisecurity .providers.AbstractAuthenticationToken" ,
72+ "org.springframework.security.core .providers.AbstractAuthenticationToken" ,
5973 "org.springframework.security.authentication.AbstractAuthenticationToken" ,
6074 null )
6175 .getVisitor ()
6276 .visitNonNull (cu , ctx );
77+ if (!cu .getImports ().equals (originalImports )) {
78+ cu = addImportIfNotExists (
79+ cu , "AbstractAuthenticationToken" , "org.springframework.security.authentication" );
6380
64- List <J .Import > originalImports = cu .getImports ();
81+ cu = addImportIfNotExists (cu , "List" , "java.util" );
82+ cu = addImportIfNotExists (cu , "Collection" , "java.util" );
83+ }
84+ originalImports = cu .getImports ();
6585
6686 cu = (J .CompilationUnit ) new ChangeType (
6787 "org.springframework.security.core.AuthenticationManager" ,
@@ -86,22 +106,218 @@ public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionCon
86106 cu , "BadCredentialsException" , "org.springframework.security.authentication" );
87107 }
88108
109+ // add java.util.Collections where UserDetails is used
110+ for (J .Import anImport : cu .getImports ()) {
111+ String importName = anImport .getQualid ().toString ();
112+ if (importName .equals ("import org.acegisecurity.userdetails.UserDetails" )
113+ || importName .equals ("org.springframework.security.core.userdetails.UserDetails" )) {
114+ cu = addImportIfNotExists (cu , "Collection" , "java.util" );
115+ }
116+ }
117+
89118 return super .visitCompilationUnit (cu , ctx );
90119 }
91120
92121 @ Override
93122 public J .MethodInvocation visitMethodInvocation (J .MethodInvocation method , ExecutionContext ctx ) {
123+ // migration of getAuthentication to getAuthentication2
94124 method = (J .MethodInvocation ) new ChangeMethodName (
95125 "jenkins.model.Jenkins getAuthentication()" , "getAuthentication2" , null , null )
96126 .getVisitor ()
97127 .visitNonNull (method , ctx );
128+
98129 // Migrate fireAuthenticated to fireAuthenticated2
99130 if (method .getSimpleName ().equals ("fireAuthenticated" )) {
100131 method = method .withName (method .getName ().withSimpleName ("fireAuthenticated2" ));
101132 }
133+
134+ // migrate loadUserByUsername to loadUserByUsername2
135+ MethodMatcher methodMatcher =
136+ new MethodMatcher ("hudson.security.SecurityRealm loadUserByUsername(java.lang.String)" , true );
137+ if (methodMatcher .matches (method )) {
138+ JavaType .Method type = method .getMethodType ();
139+
140+ if (type != null ) {
141+ type = type .withName ("loadUserByUsername2" );
142+ }
143+
144+ method = method .withName (method .getName ()
145+ .withSimpleName ("loadUserByUsername2" )
146+ .withType (type ))
147+ .withMethodType (type );
148+ }
102149 return super .visitMethodInvocation (method , ctx );
103150 }
104151
152+ @ Override
153+ public J .MethodDeclaration visitMethodDeclaration (J .MethodDeclaration method , ExecutionContext ctx ) {
154+ // migration of changing the getAuthorities() return type from GrantedAuthority[] to
155+ // Collection<GrantedAuthority>
156+ // Identify methods named `getAuthorities()`
157+ J .ClassDeclaration enclosingClass = getCursor ().firstEnclosing (J .ClassDeclaration .class );
158+ if ("getAuthorities" .equals (method .getSimpleName ())) {
159+ JavaType returnType = method .getReturnTypeExpression ().getType ();
160+
161+ // Check if the return type is an array of `GrantedAuthority`
162+ if (returnType instanceof JavaType .Array
163+ && ((JavaType .Array ) returnType )
164+ .getElemType ()
165+ .toString ()
166+ .contains ("GrantedAuthority" )) {
167+
168+ List <JRightPadded <Expression >> typeParameters = Collections .singletonList (new JRightPadded <>(
169+ new J .Identifier (
170+ UUID .randomUUID (),
171+ Space .EMPTY ,
172+ Markers .EMPTY ,
173+ "GrantedAuthority" ,
174+ JavaType .buildType ("org.springframework.security.core.GrantedAuthority" ),
175+ null ),
176+ Space .EMPTY , // No trailing space
177+ Markers .EMPTY ));
178+
179+ JContainer <Expression > typeParametersContainer = JContainer .build (typeParameters );
180+ // Change return type to `Collection<GrantedAuthority>`
181+ method = method .withReturnTypeExpression (new J .ParameterizedType (
182+ UUID .randomUUID (),
183+ Space .EMPTY ,
184+ Markers .EMPTY ,
185+ new J .Identifier (
186+ UUID .randomUUID (),
187+ Space .SINGLE_SPACE ,
188+ Markers .EMPTY ,
189+ "Collection" ,
190+ JavaType .buildType ("java.util.Collection" ),
191+ null ),
192+ typeParametersContainer ,
193+ JavaType .buildType ("java.util.Collection" )));
194+
195+ // Modify method body to return the list directly
196+ if (method .getBody () != null
197+ && !method .getBody ().getStatements ().isEmpty ()) {
198+ String grantedAuthoritiesFieldName = null ;
199+ assert enclosingClass != null ;
200+ for (J .VariableDeclarations field : enclosingClass .getBody ().getStatements ().stream ()
201+ .filter (J .VariableDeclarations .class ::isInstance )
202+ .map (J .VariableDeclarations .class ::cast )
203+ .toList ()) {
204+ if (field .getTypeExpression () != null
205+ && field .getTypeExpression ().getType () instanceof JavaType .Parameterized
206+ && ((JavaType .Parameterized ) field .getTypeExpression ()
207+ .getType ())
208+ .getType ()
209+ .toString ()
210+ .equals ("java.util.List" )
211+ && ((JavaType .Parameterized ) field .getTypeExpression ()
212+ .getType ())
213+ .getTypeParameters ()
214+ .get (0 )
215+ .toString ()
216+ .equals ("org.springframework.security.core.GrantedAuthority" )) {
217+ grantedAuthoritiesFieldName =
218+ field .getVariables ().get (0 ).getSimpleName ();
219+ break ;
220+ }
221+ }
222+
223+ if (grantedAuthoritiesFieldName != null ) {
224+ method = method .withBody (method .getBody ()
225+ .withStatements (Collections .singletonList (new J .Return (
226+ UUID .randomUUID (),
227+ Space .format ("\n " + " " .repeat (8 )),
228+ Markers .EMPTY ,
229+ new J .Identifier (
230+ UUID .randomUUID (),
231+ Space .SINGLE_SPACE ,
232+ Markers .EMPTY ,
233+ grantedAuthoritiesFieldName ,
234+ JavaType .buildType ("java.util.List" ),
235+ null )))));
236+ } else {
237+ method = method .withBody (method .getBody ()
238+ .withStatements (method .getBody ().getStatements ().stream ()
239+ .map (statement -> {
240+ // Check if the statement is a return statement with `new
241+ // GrantedAuthority[0]`
242+ if (statement instanceof J .Return ) {
243+ J .Return returnStatement = (J .Return ) statement ;
244+ if (returnStatement .getExpression () instanceof J .Ternary ) {
245+ J .Ternary ternaryExpression =
246+ (J .Ternary ) returnStatement .getExpression ();
247+ if (ternaryExpression .getFalsePart ()
248+ instanceof J .NewArray ) {
249+ J .NewArray newArrayExpression =
250+ (J .NewArray ) ternaryExpression .getFalsePart ();
251+ if (newArrayExpression
252+ .getType ()
253+ .toString ()
254+ .contains ("GrantedAuthority[]" )
255+ && newArrayExpression
256+ .getDimensions ()
257+ .get (0 )
258+ .toString ()
259+ .contains ("[0]" )) {
260+ LOG .info (
261+ "Found `new GrantedAuthority[0]` inside a ternary expression in getAuthorities method" );
262+ // Replace `new GrantedAuthority[0]` with
263+ // `List.of()` in the ternary expression
264+ ternaryExpression = ternaryExpression .withFalsePart (
265+ new J .Identifier (
266+ UUID .randomUUID (),
267+ Space .SINGLE_SPACE ,
268+ Markers .EMPTY ,
269+ "List.of()" ,
270+ JavaType .buildType (
271+ "java.util.List" ),
272+ null ));
273+ }
274+ }
275+ return returnStatement .withExpression (
276+ ternaryExpression ); // Update the return statement
277+ // with the modified ternary
278+ }
279+ }
280+ return statement ; // Return the unchanged statement if it's not a
281+ // `new GrantedAuthority[0]`
282+ })
283+ .collect (Collectors .toList ())));
284+ }
285+ }
286+ }
287+ }
288+
289+ // Migrate loadUserByUsername to loadUserByUsername2 method declaration if the class extends Security
290+ // Realm
291+ MethodMatcher methodMatcher =
292+ new MethodMatcher ("hudson.security.SecurityRealm loadUserByUsername(java.lang.String)" , true );
293+ if (enclosingClass != null
294+ && enclosingClass .getExtends () != null
295+ && enclosingClass .getExtends ().getType () != null
296+ && enclosingClass .getExtends ().getType ().toString ().equals ("hudson.security.SecurityRealm" )) {
297+
298+ // Check if the overriding method is named loadUserByUsername
299+ if (methodMatcher .matches (method , enclosingClass )) {
300+ JavaType .Method type = method .getMethodType ();
301+
302+ if (method .getMethodType ().getOverride () != null ) {
303+ LOG .info (
304+ "Don't migrate this one to loadUserByUsername2 {}" ,
305+ method .getMethodType ().getOverride ().toString ());
306+ return super .visitMethodDeclaration (method , ctx );
307+ }
308+ if (type != null ) {
309+ type = type .withName ("loadUserByUsername2" );
310+ }
311+ method = method .withName (method .getName ()
312+ .withSimpleName ("loadUserByUsername2" )
313+ .withType (type ))
314+ .withMethodType (type );
315+ }
316+ }
317+
318+ return super .visitMethodDeclaration (method , ctx );
319+ }
320+
105321 private J .CompilationUnit addImportIfNotExists (J .CompilationUnit cu , String className , String packageName ) {
106322 boolean importExists = cu .getImports ().stream ().anyMatch (anImport -> (packageName + "." + className )
107323 .equals (anImport .getQualid ().toString ()));
0 commit comments