stormpath-sdk-java
stormpath-sdk-java copied to clipboard
expose a bean containing a map of Group name key and href value pairs
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.
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.
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...
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 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 executegroups['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?)
@dogeared just a minor comment, remember to use @PreAuthorize("hasAuthority(XX)") rather than @PreAuthorize("hasRole(XX)")
@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 @mrioan - I updated the sample code above. Thanks.