Mikhail Mazursky (Migrated from SEC-1908) said:
I was updating spring 3.0.x to 3.1.0 and one of my tests (with Mockito) showed a compilation error. The problem i encountered was the same as described here 1:
LdapAuthoritiesPopulator authoritiesPopulator = mock(LdapAuthoritiesPopulator.class);
when(authoritiesPopulator.getGrantedAuthorities(userData, USERNAME)).thenReturn(AuthorityUtils.NO_AUTHORITIES);
This is not type safe but that problem can be worked around by:
doReturn(AuthorityUtils.NO_AUTHORITIES).when(authoritiesPopulator).getGrantedAuthorities(userData, USERNAME);
The question is should the LdapAuthoritiesPopulator interface's method getGrantedAuthorities have a bounded wildcard return type or not? I think it's better to remove wildcard as it gives nothing to the calling code.
Spring 3.0.x have it as:
Collection
getGrantedAuthorities(DirContextOperations userData, String username); and 3.1.0 as:
Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username);
The same problem with GrantedAuthoritiesMapper, GrantedAuthoritiesContainer, Attributes2GrantedAuthoritiesMapper, WebSpherePreAuthenticatedWebAuthenticationDetailsSource and possibly some other classes/ifaces.
Interesting reading on the topic 2.
Methods with bounded wildcard return types
PUBLIC
- [ ] ~.FindBoundedWildcardsTest$Here#here
- [x] ~.access.annotation.AnnotationMetadataExtractor#extractAttributes
- [x] ~.access.annotation.BusinessService#methodReturningAList
- [x] ~.access.annotation.BusinessServiceImpl#methodReturningAList
- [x] ~.access.annotation.ExpressionProtectedBusinessServiceImpl#methodReturningAList
- [x] ~.access.annotation.Jsr250BusinessServiceImpl#methodReturningAList
- [x] ~.access.annotation.SecuredAnnotationSecurityMetadataSourceTests$CustomSecurityAnnotationMetadataExtractor#extractAttributes
- [x] ~.access.expression.method.PrePostAnnotationSecurityMetadataSourceTests$ReturnAList#doSomething
- [x] ~.access.expression.method.PrePostAnnotationSecurityMetadataSourceTests$ReturnAListImpl1#doSomething
- [x] ~.access.expression.method.PrePostAnnotationSecurityMetadataSourceTests$ReturnAListImpl2#doSomething
- [x] ~.access.expression.method.PrePostAnnotationSecurityMetadataSourceTests$ReturnAnotherList#doSomething
- [x] ~.access.expression.method.PrePostAnnotationSecurityMetadataSourceTests$ReturnAnotherListImpl1#doSomething
- [x] ~.access.expression.method.PrePostAnnotationSecurityMetadataSourceTests$ReturnAnotherListImpl2#doSomething
- [x] ~.access.hierarchicalroles.NullRoleHierarchy#getReachableGrantedAuthorities
- [x] ~.access.hierarchicalroles.RoleHierarchy#getReachableGrantedAuthorities
- [x] ~.access.hierarchicalroles.RoleHierarchyAuthoritiesMapper#mapAuthorities
- [x] ~.access.intercept.AbstractSecurityInterceptor#getSecureObjectClass
- [x] ~.access.intercept.AbstractSecurityInterceptorTests$MockSecurityInterceptorReturnsNull#getSecureObjectClass
- [x] ~.access.intercept.AbstractSecurityInterceptorTests$MockSecurityInterceptorWhichOnlySupportsStrings#getSecureObjectClass
- [x] ~.access.intercept.RunAsUserToken#getOriginalAuthentication
- [x] ~.access.intercept.aopalliance.MethodSecurityInterceptor#getSecureObjectClass
- [x] ~.access.vote.AbstractAccessDecisionManager#getDecisionVoters
- [x] ~.access.vote.AbstractAclVoter#getProcessDomainObjectClass
- [x] ~.authentication.event.InteractiveAuthenticationSuccessEvent#getGeneratedBy
- [x] ~.authorization.method.PreAuthorizeAuthorizationManagerTests$TestTargetClassAware#getTargetClass
- [x] ~.authorization.method.SecuredAuthorizationManagerTests$TestTargetClassAware#getTargetClass
- [x] ~.concurrent.DelegatingSecurityContextExecutorService#submit
- [x] ~.concurrent.DelegatingSecurityContextScheduledExecutorService#schedule
- [x] ~.concurrent.DelegatingSecurityContextScheduledExecutorService#scheduleAtFixedRate
- [x] ~.concurrent.DelegatingSecurityContextScheduledExecutorService#scheduleWithFixedDelay
- [x] ~.config.annotation.AbstractConfiguredSecurityBuilder#getSharedObjects
- [x] ~.config.annotation.web.FormLoginDsl#getAuthenticationDetailsSource
- [x] ~.config.annotation.web.HttpBasicDsl#getAuthenticationDetailsSource
- [x] ~.config.annotation.web.OAuth2LoginDsl#getAuthenticationDetailsSource
- [x] ~.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry$MatcherBuilder#build
- [x] ~.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry$PathMatcherMessageMatcherBuilder#build
- [x] ~.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry$PreBuiltMatcherBuilder#build
- [x] ~.config.annotation.web.oauth2.resourceserver.JwtDsl#getJwtAuthenticationConverter
- [x] ~.config.annotation.web.oauth2.resourceserver.JwtDslTests$CustomJwtAuthenticationConverterConfig$Companion#getCONVERTER
- [x] ~.config.authentication.AuthenticationManagerFactoryBean#getObjectType
- [x] ~.config.core.userdetails.ReactiveUserDetailsServiceResourceFactoryBean#getObjectType
- [x] ~.config.core.userdetails.UserDetailsMapFactoryBean#getObjectType
- [x] ~.config.core.userdetails.UserDetailsResourceFactoryBean#getObjectType
- [x] ~.config.http.HandlerMappingIntrospectorFactoryBean#getObjectType
- [x] ~.config.http.HttpConfigurationBuilder$SecurityContextHolderStrategyFactory#getObjectType
- [x] ~.config.http.OAuth2ResourceServerBeanDefinitionParser$NimbusJwtDecoderJwkSetUriFactoryBean#getObjectType
- [x] ~.config.http.OAuth2ResourceServerBeanDefinitionParserTests$ClockFactoryBean#getObjectType
- [x] ~.config.http.OAuth2ResourceServerBeanDefinitionParserTests$JwtDecoderFactoryBean#getObjectType
- [x] ~.config.http.OAuth2ResourceServerBeanDefinitionParserTests$MockWebServerFactoryBean#getObjectType
- [x] ~.config.http.OAuth2ResourceServerBeanDefinitionParserTests$MockWebServerPropertiesFactoryBean#getObjectType
- [x] ~.config.http.OAuth2ResourceServerBeanDefinitionParserTests$OpaqueTokenIntrospectorFactoryBean#getObjectType
- [x] ~.config.ldap.EmbeddedLdapServerContextSourceFactoryBean#getObjectType
- [x] #11805
- [x] #11804
- [x] #11803
- [x] #11802
- [x] #11801
- [x] ~.config.provisioning.UserDetailsManagerResourceFactoryBean#getObjectType
- [ ] ~.config.web.server.ServerJwtDsl#getJwtAuthenticationConverter
- [ ] ~.config.web.server.ServerJwtDslTests$CustomJwtAuthenticationConverterConfig$Companion#getCONVERTER
- [ ] ~.config.websocket.WebSocketMessageBrokerConfigTests$ExceptingInterceptor#preSend
- [ ] ~.config.websocket.WebSocketMessageBrokerSecurityBeanDefinitionParser$SecurityContextHolderStrategyFactory#getObjectType
- [x] ~.core.Authentication#getAuthorities
- [x] ~.core.authority.GrantedAuthoritiesContainer#getGrantedAuthorities
- [x] ~.core.authority.mapping.Attributes2GrantedAuthoritiesMapper#getGrantedAuthorities
- [x] ~.core.authority.mapping.GrantedAuthoritiesMapper#mapAuthorities
- [x] ~.core.authority.mapping.NullAuthoritiesMapper#mapAuthorities
- [x] ~.core.userdetails.UserDetails#getAuthorities
- [ ] ~.jackson2.UnmodifiableMapDeserializer#deserialize
- [x] ~.ldap.authentication.UserDetailsServiceLdapAuthoritiesPopulator#getGrantedAuthorities
- [x] ~.ldap.userdetails.LdapAuthoritiesPopulator#getGrantedAuthorities
- [ ] ~.messaging.access.intercept.AuthorizationChannelInterceptor#preSend
- [ ] ~.messaging.access.intercept.ChannelSecurityInterceptor#getSecureObjectClass
- [ ] ~.messaging.access.intercept.ChannelSecurityInterceptor#postReceive
- [ ] ~.messaging.access.intercept.ChannelSecurityInterceptor#preSend
- [ ] ~.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager$Builder#build
- [ ] ~.messaging.context.SecurityContextChannelInterceptor#beforeHandle
- [ ] ~.messaging.context.SecurityContextChannelInterceptor#preSend
- [ ] ~.messaging.web.csrf.CsrfChannelInterceptor#preSend
- [ ] ~.oauth2.client.endpoint.AbstractOAuth2AuthorizationGrantRequestEntityConverter#convert
- [ ] ~.oauth2.client.oidc.authentication.OidcIdTokenDecoderFactory#createDefaultClaimTypeConverters
- [ ] ~.oauth2.client.oidc.authentication.ReactiveOidcIdTokenDecoderFactory#createDefaultClaimTypeConverters
- [ ] ~.oauth2.client.oidc.userinfo.OidcReactiveOAuth2UserService#createDefaultClaimTypeConverters
- [ ] ~.oauth2.client.oidc.userinfo.OidcUserService#createDefaultClaimTypeConverters
- [ ] ~.oauth2.client.userinfo.OAuth2UserRequestEntityConverter#convert
- [ ] ~.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction#defaultRequest
- [x] ~.oauth2.core.DefaultOAuth2AuthenticatedPrincipal#getAuthorities
- [x] ~.oauth2.core.OAuth2AuthenticatedPrincipal#getAuthorities
- [x] ~.oauth2.core.user.DefaultOAuth2User#getAuthorities
- [x] ~.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal#getAuthorities
- [x] ~.provisioning.MutableUser#getAuthorities
- [ ] ~.scheduling.DelegatingSecurityContextTaskScheduler#schedule
- [ ] ~.scheduling.DelegatingSecurityContextTaskScheduler#scheduleAtFixedRate
- [ ] ~.scheduling.DelegatingSecurityContextTaskScheduler#scheduleWithFixedDelay
- [ ] ~.task.DelegatingSecurityContextAsyncTaskExecutor#submit
- [x] ~.test.context.showcase.CustomUserDetails#getAuthorities
- [ ] ~.test.context.support.WithSecurityContext#factory
- [ ] ~.web.access.intercept.FilterSecurityInterceptor#getSecureObjectClass
- [x] ~.web.authentication.switchuser.SwitchUserAuthorityChanger#modifyGrantedAuthorities
- [ ] ~.web.authentication.www.BasicAuthenticationConverter#getAuthenticationDetailsSource
PROTECTED
- [ ] ~.acls.afterinvocation.AbstractAclProvider#getProcessDomainObjectClass
- [ ] ~.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer$AuthorizedUrl#getMatchers
- [ ] ~.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer$AuthorizedUrl#getMatchers
- [ ] ~.config.annotation.web.configurers.UrlAuthorizationConfigurer$AuthorizedUrl#getMatchers
- [ ] ~.config.web.server.ServerHttpSecurity$OAuth2ResourceServerSpec$JwtSpec#getJwtAuthenticationConverter
- [x] ~.ldap.authentication.AbstractLdapAuthenticationProvider#loadUserAuthorities
- [x] ~.ldap.authentication.LdapAuthenticationProvider#loadUserAuthorities
- [x] ~.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider#loadUserAuthorities
- [ ] ~.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter#getAuthenticationDetailsSource
- [ ] ~.web.authentication.rememberme.AbstractRememberMeServices#getAuthenticationDetailsSource
DEFAULT
- [ ] ~.access.vote.RoleHierarchyVoter#extractAuthorities
- [ ] ~.access.vote.RoleVoter#extractAuthorities
- [ ] ~.authentication.AuthenticationTrustResolverImpl#getAnonymousClass
- [ ] ~.authentication.AuthenticationTrustResolverImpl#getRememberMeClass
- [ ] ~.config.annotation.ObjectPostProcessorTests$PerformConversion#perform
- [ ] ~.config.annotation.web.configurers.AbstractInterceptUrlConfigurer#getDecisionVoters
- [ ] ~.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer#getDecisionVoters
- [ ] ~.config.annotation.web.configurers.NamespaceHttpBasicTests$AuthenticationDetailsSourceHttpBasicConfig#authenticationDetailsSource
- [ ] ~.config.annotation.web.configurers.NamespaceHttpBasicTests$AuthenticationDetailsSourceHttpBasicLambdaConfig#authenticationDetailsSource
- [ ] ~.config.annotation.web.configurers.UrlAuthorizationConfigurer#getDecisionVoters
- [ ] ~.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer$JwtConfigurer#getJwtAuthenticationConverter
- [ ] ~.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurerTests$CustomAuthenticationDetailsSource#authenticationDetailsSource
- [ ] ~.config.annotation.web.socket.WebSocketMessageBrokerSecurityConfigurationDocTests$WebSocketSecurityConfig#authorizationManager
- [ ] ~.config.annotation.web.socket.WebSocketMessageBrokerSecurityConfigurationTests$DefaultPatternMatcherConfig#authorizationManager
- [ ] ~.config.annotation.web.socket.WebSocketMessageBrokerSecurityConfigurationTests$MsmsRegistryCustomPatternMatcherConfig#authorizationManager
- [ ] ~.config.annotation.web.socket.WebSocketMessageBrokerSecurityConfigurationTests$OverrideMsmsRegistryCustomPatternMatcherConfig#authorizationManager
- [ ] ~.config.annotation.web.socket.WebSocketMessageBrokerSecurityConfigurationTests$SockJsProxylessSecurityConfig#authorizationManager
- [ ] ~.config.annotation.web.socket.WebSocketMessageBrokerSecurityConfigurationTests$SockJsSecurityConfig#authorizationManager
- [ ] ~.config.annotation.web.socket.WebSocketMessageBrokerSecurityConfigurationTests$WebSocketSecurityConfig#authorizationManager
- [ ] ~.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager$Entry#getMessageMatcher
PRIVATE
- [ ] ~.aot.hint.CoreSecurityRuntimeHintsTests#getAuthenticationEvents
- [ ] ~.aot.hint.CoreSecurityRuntimeHintsTests#getAuthenticationExceptions
- [ ] ~.authentication.DefaultAuthenticationEventPublisher#getEventConstructor
- [ ] ~.authorization.AuthorityAuthorizationManager#getGrantedAuthorities
- [ ] ~.authorization.method.AuthorizationManagerAfterReactiveMethodInterceptor#postAuthorize
- [ ] ~.authorization.method.PostFilterAuthorizationReactiveMethodInterceptor#filterMultiValue
- [ ] ~.authorization.method.PostFilterAuthorizationReactiveMethodInterceptor#filterSingleValue
- [ ] ~.authorization.method.PostFilterAuthorizationReactiveMethodInterceptor#postFilter
- [ ] ~.authorization.method.PreFilterAuthorizationReactiveMethodInterceptor#filterMultiValue
- [ ] ~.authorization.method.PreFilterAuthorizationReactiveMethodInterceptor#filterSingleValue
- [ ] ~.config.annotation.web.builders.HttpSecurityAddFilterTest#assertThatFilters
- [ ] ~.config.annotation.web.configuration.HttpSecurityConfiguration#createSharedObjects
- [ ] ~.config.annotation.web.configuration.WebSecurityConfigurerAdapter#createSharedObjects
- [ ] ~.config.annotation.web.configurers.NamespaceDebugTests#filterChainClass
- [ ] ~.config.annotation.web.configurers.NamespaceHttpCustomFilterTests#assertThatFilters
- [ ] ~.config.http.UserDetailsServiceFactoryBean#getBeansOfType
- [ ] ~.config.ldap.ContextSourceSettingPostProcessor#getContextSourceClass
- [ ] ~.config.websocket.WebSocketMessageBrokerConfigTests#message
- [ ] ~.config.websocket.WebSocketMessageBrokerSecurityBeanDefinitionParser$MessageMatcherDelegatingAuthorizationManagerFactory#createMessageMatcherDelegatingAuthorizationManager
- [ ] ~.htmlunit.server.HtmlUnitWebTestClient#content
- [ ] ~.jackson2.SecurityJackson2Modules#createAllowlistedDefaultTyping
- [ ] ~.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager#authorizationContext
- [ ] ~.oauth2.client.oidc.authentication.OidcIdTokenDecoderFactory#getConverter
- [ ] ~.oauth2.client.oidc.authentication.ReactiveOidcIdTokenDecoderFactory#getConverter
- [ ] ~.oauth2.client.oidc.userinfo.OidcReactiveOAuth2UserService#getConverter
- [ ] ~.oauth2.client.oidc.userinfo.OidcUserService#getConverter
- [ ] ~.oauth2.client.userinfo.DefaultReactiveOAuth2UserService#getRequestHeaderSpec
- [ ] ~.oauth2.core.converter.ClaimTypeConverterTests#getConverter
- [ ] ~.oauth2.core.oidc.user.TestOidcUsers#authorities
- [ ] ~.oauth2.jwt.MappedJwtClaimSetConverter#getConverter
- [ ] ~.oauth2.server.resource.authentication.JwtAuthenticationProviderTests#errorCode
- [ ] ~.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector#defaultRequestEntityConverter
- [ ] ~.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector#defaultRequestEntityConverter
- [ ] ~.saml2.provider.service.authentication.OpenSamlAuthenticationProvider#getAssertionAuthorities
- [ ] ~.test.context.support.WithSecurityContextTestExecutionListener#createFactory
- [ ] ~.web.authentication.preauth.websphere.DefaultWASUsernameAndGroupsExtractor#getClass
- [ ] ~.web.authentication.preauth.websphere.DefaultWASUsernameAndGroupsExtractor#getWSCredentialClass
- [ ] ~.web.authentication.preauth.websphere.WebSpherePreAuthenticatedWebAuthenticationDetailsSource#getWebSphereGroupsBasedGrantedAuthorities
Comment From: spring-projects-issues
Luke Taylor said:
This was requested in SEC-1550, to cater for classes which use custom GrantedAuthority implementations.
Comment From: spring-projects-issues
Mikhail Mazursky said:
From the mentioned issue i still can't see any benefit to return bounded wildcad types.
When i use ??void test(List<? super T> arg)?? method signature that allows me to safely pass lists of child types (U extends T) to method. What's the point to return bounded wildcard types? As you said in those issue ??You can still only read the upper bound of the wildcard from the collection??.
Wildcard only helps to avoid in-method cast from ??List