-
Notifications
You must be signed in to change notification settings - Fork 71
Description
Hello! I'd like to report an issue related to OpenID Connect (OIDC) and the roles-claim: Shinyproxy does not support parsing a roles claim from OIDC userinfo.
I am configuring a new ShinyProxy installation, using OpenID Connect. The IdP is running Shibboleth. (Shibboleth has been known for a long time as a SAML IdP; since version 3.x, Shibboleth has supported OIDC as an IdP.) ShinyProxy is configured with Auth/Token/Userinfo/JWKS URls, and PKCE is enabled.
In my case, the roles information is contained in an OIDC claim named eduPersonEntitlement, and to get this claim, I need to request the scope eduperson_entitlement. I have confirmed that ShinyProxy is properly requesting this scope from the IdP (I can see it when I look at the HTTP requests using Firefox dev tools). I have talked to the Shibboleth admins, and they confirmed I am making the request properly, and that the eduPersonEntitlement claim is being provided.
I turned on auth debugging, so I could see the claims that were being examined, but I still did not see my eduPersonEntitlement claim. I also noticed that some other claims were not being provided. I started to wonder if the userinfo endpoint was not being checked.
Eventually, I found createAuthoritiesMapper in eu.openanalytics.containerproxy.auth.OpenIDAuthenticationBackend:
Lines 209 to 240 in 2c71c88
| protected GrantedAuthoritiesMapper createAuthoritiesMapper() { | |
| String rolesClaimName = environment.getProperty("proxy.openid.roles-claim"); | |
| if (rolesClaimName == null || rolesClaimName.isEmpty()) { | |
| return authorities -> authorities; | |
| } else { | |
| return authorities -> { | |
| Set<GrantedAuthority> mappedAuthorities = new HashSet<>(); | |
| for (GrantedAuthority auth: authorities) { | |
| if (auth instanceof OidcUserAuthority) { | |
| OidcIdToken idToken = ((OidcUserAuthority) auth).getIdToken(); | |
| if (log.isDebugEnabled()) { | |
| String lineSep = System.getProperty("line.separator"); | |
| String claims = idToken.getClaims().entrySet().stream() | |
| .map(e -> String.format("%s -> %s", e.getKey(), e.getValue())) | |
| .collect(Collectors.joining(lineSep)); | |
| log.debug(String.format("Checking for roles in claim '%s'. Available claims in ID token (%d):%s%s", | |
| rolesClaimName, idToken.getClaims().size(), lineSep, claims)); | |
| } | |
| Object claimValue = idToken.getClaims().get(rolesClaimName); | |
| for (String role: parseRolesClaim(log, rolesClaimName, claimValue)) { | |
| String mappedRole = role.toUpperCase().startsWith("ROLE_") ? role : "ROLE_" + role; | |
| mappedAuthorities.add(new SimpleGrantedAuthority(mappedRole.toUpperCase())); | |
| } | |
| } | |
| } | |
| return mappedAuthorities; | |
| }; | |
| } | |
| } |
I see the code is looking at the ID Token (on line 218), but it doesn't look like the userinfo is being checked. So, I think that is the problem: When looking for the roles, only the ID Token is being checked, not the userinfo.
Although I was able to find (what I think is) the issue, I do not have the Java skills necessary to patch, build, or test.
Please let me know if you have any questions, or if I put this report in the wrong place. Thanks very much!