stormpath-sdk-java icon indicating copy to clipboard operation
stormpath-sdk-java copied to clipboard

expose a bean containing a map of Group name key and href value pairs

Open dogeared opened this issue 9 years ago • 7 comments

In order to assist users with creating method level authorization, we can expose a bean containing name value pairs of Stormpath Group information to be used in SpringEL expressions.

A reference implementation is as follows:

StormpathSpringSecurityAutoConfiguration:

    @Bean
    @Override
    @ConditionalOnMissingBean(name="stormpathAuthorities")
    public Map<String, String> stormpathAuthorities() {
        return super.stormpathAuthorities();
    }

AbstractStormpathSpringSecurityConfiguration:

    public Map<String, String> stormpathAuthorities() {
        Map<String, String> ret = new HashMap<>();

        for (Group group : application.getGroups()) {
            ret.put(group.getName(), group.getHref());
        }

        return ret;
    }

With this setup, the following SpringEL would be valid:

    @PreAuthorize("hasAuthority(@stormpathAuthorities['admin'])")
    public void ensureAdmin() {}

PROVIDED that there was a Stormpath Group named admin in a Directory mapped to the Application.

The above would ensure that only authenticated Accounts that are members of the admin group would be granted access to the method.

dogeared avatar Jul 08 '16 19:07 dogeared

FWIW, I think this is one bean we shouldn't name with a stormpath prefix. As a user of our stuff, I'd hate to write that in every check - it couples my code (conceptually) to a stormpath-named bean.

Instead, I'd prefer we just use 'groups'

public Map<String, String> groups() {
    Map<String, String> ret = new HashMap<>();
    for (Group group : application.getGroups()) {
        ret.put(group.getName(), group.getHref());
    }
    return ret;
}

resulting in:

@PreAuthorize("hasRole(@groups['admin'])")
public void ensureAdmin() {}

Much nicer IMO.

lhazlewood avatar Jul 08 '16 20:07 lhazlewood

actually, even nicer, would be to have hasRole('admin') 'just work' without referencing a bean at all. I'm sure there is a way to get this to work...

lhazlewood avatar Jul 08 '16 20:07 lhazlewood

another idea:

Let's say that a user defines the following config:

stormpath:
  roles:
    admin: 'https://api.stormpath.com/v1/groups/sOmEgrOuPID'

Then a check for hasRole('admin') should assume the specified href and only fall back to the auto-discovered groups map.

Additionally, with this logic in place, we can go back to the stormpathGroups bean name since users wouldn't likely reference it directly.

lhazlewood avatar Jul 08 '16 20:07 lhazlewood

@lhazlewood to the best of my understanding something as simple as hasRole('admin') will not be dynamic, admin is just a hard-coded string here

@dogeared and me have already thought/analyzed different options in the past and the notation hasRole(@groups['admin']) would be the simplest.

  • hasRole: is the operation that Spring Security will execute
  • groups['admin'] would be the variable argument.

Maybe something like hasRole(@admin) could be done. This implies that there must be a single bean per role. So we will end up having things like hasRole(@user), hasRole(@admin), hasRole(@ops), etc. We need to investigate this, not even sure how that will be used by developers (they specify names in config and we map that to bean instances?)

mrioan avatar Jul 08 '16 20:07 mrioan

@dogeared just a minor comment, remember to use @PreAuthorize("hasAuthority(XX)") rather than @PreAuthorize("hasRole(XX)")

mrioan avatar Jul 08 '16 21:07 mrioan

@dogeared Yes, @mrioan is correct. hasAuthority should be used and we should discourage the use of hasRole due to the ROLE_ prefix issue. See https://github.com/stormpath/stormpath-sdk-java/pull/750 for more info.

mraible avatar Jul 11 '16 11:07 mraible

@mraible @mrioan - I updated the sample code above. Thanks.

dogeared avatar Jul 11 '16 16:07 dogeared