Search code examples
javaspringspring-securityoauth-2.0spring-oauth2

Spring OAuth2 custom grant type autowiring a class returns null


I have a problem with Spring Security OAuth2. There is a kiosk system where all the kiosks need to authorize with a central OAuth2 provider during launch. There are two stores for credentials -- one for actual users (e.g technicians) and another one for kiosks. The collection for kiosks store kiosk profile information, which is essentially serial numbers of all the devices used in a kiosk (bill acceptor, cash dispenser, thermal printer etc).

So, here is the flow that I am trying to achieve.

  • Kiosk sends its profile information to /oauth/token with grant_type=kiosk
  • If profile exists, OAuth2 gives the token and everything is great
  • If profile does not exist, the kiosk profile is added to the kiosks collection with state "off" and OAuth2 gives 401 Unauthorized

Now, I have created a new grant type for kiosk authorization. But I need a way to access my Kiosk Profile Data Mapper, which is a Spring service. So, in my class I add the following:

class KioskTokenGranter extends AbstractTokenGranter {
    @Autowire
    KioskProfileService kioskProfile;

    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
          // request parsing stuff
          kioskProfile.findByAttributes(...);
    }
}

The snipper above gives me a NullPointerException that kioskProfile does not exist. If I do the same thing in AuthorizationServerConfigurerAdapter, autowire works. So, my question is how to Autowire a service inside TokenGranter.


Solution

  • It appears you're just running into the plain old problem where the objects you are instantiating aren't controlled by Spring. You haven't annotated your class as a @Component or anything like that (not that I would recommend you do in this case). Spring isn't aware of your @Autowire annotation.

    For another example of someone's implementation of AbstractTokenGranter, take OBOTokenGranter.java.

     public class OBOTokenGranter extends AbstractTokenGranter {
    
        ...
    
        private UserDetailsService uds;
    
        public OBOTokenGranter(UserDetailsService uds, AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
            OAuth2RequestFactory requestFactory) {
           super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
    
           this.uds = uds;
       }
    
       ...
     }
    

    Note that UserDetailsService uds is being passed in via the constructor instead of autowired in. You can see the usaged of OBOTokenGranter in OBOTokenGenerator.java, which is a @RestController and has the UserDetailService autowired into it, so that it can be used in construction of the Granter.

     @RestController
     public class OBOTokenGenerator {
    
     ...
    
        @Autowired
        private UserDetailsService uds;
    
     ...
        @RequestMapping("/obo/{user}")
        public ResponseEntity<OAuth2AccessToken> getOBOToken(Principal principal, @PathVariable("user") String user) {
    
     ...
    
            OBOTokenGranter granter = new OBOTokenGranter(uds, tokenServices, clientDetailsService, requestFactory);
    
     ...
     }
    

    So the question remaining is: does your code follow this pattern of usage? Do you have a Controller/Service/Component/etc that constructs the KioskTokenGranter?