-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#4941 - Mapping OIDC groups to INCEpTION's internal roles #4982
base: main
Are you sure you want to change the base?
#4941 - Mapping OIDC groups to INCEpTION's internal roles #4982
Conversation
…efore cleaning and refactoring the feature
Updating branch with latest devs from main
Updated with latest main commits
… a dedicated file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion! I hope you find my feedback useful.
|
||
@Configuration | ||
@ConfigurationProperties(prefix = "oauth2-groups") | ||
public class OAuth2Utils { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Utils classes in INCEpTION are typically final classes containing only static methods. Configuration classes are called XxxPropertiesImpl
, e.g. KnowledgeBasePropertiesImpl
and come with a respective interface, e.g. KnowledgeBaseProperties
. This class/interface separation is necessary in cases where the properties are injected into Wicket code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@reckart how would you recommend to proceed? Creating the interface and implementation class for the properties, injecting the PropertiesImpl class in OAuth2AdapterImpl's constructor and moving the mapping logic in a private method of that class?
@ConfigurationProperties(prefix = "oauth2-groups") | ||
public class OAuth2Utils { | ||
|
||
private static boolean OAUTH2_GROUPS_ENABLED; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fields should be non-static and use camelCase.
} | ||
|
||
|
||
public static Set<Role> getOAuth2UserRoles(User aUser, ArrayList<String> oauth2groups) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Arguments should use interfaces for collections. e.g. List
instead of ArrayList
.
public static Set<Role> getOAuth2UserRoles(User aUser, ArrayList<String> oauth2groups) | ||
throws AccessDeniedException | ||
{ | ||
Set<Role> roles = new HashSet<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use var
when possible.
+ aUser.getUsername() + "] doesn't have any groups, or the corresponding claim is empty"); | ||
} | ||
|
||
oauth2groups.forEach(group -> matchOauth2groupToRole(group, roles)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Functional programming (without side-effects) would be easier to understand. Can we use map
instead of forEach
here?
|
||
Set<Role> userRoles = OAuth2Utils.getOAuth2UserRoles(testUser, userOAuth2Groups); | ||
|
||
assertTrue(userRoles.contains(Role.ROLE_USER)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use AssertJ asserts instead of Unit asserts.
|
||
ArrayList<String> userOAuth2Groups = new ArrayList<>(); | ||
|
||
try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assertThatExceptionOfType(...).isThrownBy(() -> { ... })
|
||
@ExtendWith(SpringExtension.class) | ||
@ContextConfiguration(classes = OAuth2Utils.class) | ||
@DirtiesContext(classMode = ClassMode.AFTER_CLASS) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of making this a spring integration test, I'd tend towards it being a plain junit test that sets up the necessary beans as POJOs. It seems a bit of overkill to start up an entire spring context for this.
import de.tudarmstadt.ukp.clarin.webanno.security.model.User; | ||
|
||
@Configuration | ||
@ConfigurationProperties(prefix = "oauth2-groups") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
security.oauth2.roles...
? Other INCEpTION security properties live under security...
. Mind, INCEpTION has no groups, only roles. It is incidental that you call these labels groups
on your side. So from the INCEpTION perspective, we are mapping roles, not groups.
security.oauth.roles.enabled=true
security.oauth.roles.claim=groups
security.oauth.roles.mapping.ROLE_USER=ad-user
security.oauth.roles.mapping.ROLE_ADMIN=ad-admin
security.oauth.roles.mapping.ROLE_PROJECT_CREATOR=ad-project-creator
security.oauth.roles.mapping....=...
@@ -148,6 +147,10 @@ private User fetchOrMaterializeUser(OAuth2UserRequest userRequest, OAuth2User us | |||
if (u != null) { | |||
denyAccessToDeactivatedUsers(u); | |||
denyAccessOfRealmsDoNotMatch(realm, u); | |||
|
|||
u.setRoles(OAuth2Utils.getOAuth2UserRoles(u, user.getAttribute("groups"))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The claim should be configurable via the properties as well since this is not a well-defined name. Others might e.g. use a roles
claim instead.
Btw. the commit message convention for INCEpTION goes like this:
|
- OAuth2 Role Claim is now congigurable - Updated config prefix for the feature to 'security.oauth.roles'
- Updated branch with latest commits from `main`
The PR build fails but I have no idea why. I have opened a support discussion: https://github.com/orgs/community/discussions/138018 |
What's in the PR
This PR contains the feature allowing to map OAuth2 groups with INCEpTION roles, as described in the corresopnding feaure request
How to test manually
INCEPTION_ADMIN
INCEPTION_USER
INCEPTION_PROJECT_CREATOR
INCEPTION_REMOTE
settings.properties
file, inside your INCEpTION home directory :settings.properties
file. You can play with the mapping/groups to test the behavior.Note : :
OAuth2AdaptaterImpl
class was vefore calling to thePreAuthUtil
class, whereas it's specified in the documentation that theExternal PreAuth
feature isn't compatible with OAuth2 authentication. I made a dedicatedOAuth2Utils
class that contains a method that maps the OAuth2 groups if the mapping feature is enabled, or just adds theUSER
INCEpTION role to the user if the mapping feature is disabled.@Configuration
annotation.Automatic testing
OAuth2UtilsTest
contains a set of unit testsDocumentation
I'm of course open to feedback and willing to modify the implementation if needed ;)