-
Notifications
You must be signed in to change notification settings - Fork 99
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
Add support for avatars #523
base: master
Are you sure you want to change the base?
Conversation
FYI @timja thanks for the help, jenkinsci/azure-ad-plugin#658 was a good inspiration for it |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #523 +/- ##
============================================
+ Coverage 72.04% 72.45% +0.40%
- Complexity 235 249 +14
============================================
Files 18 20 +2
Lines 1073 1118 +45
Branches 149 154 +5
============================================
+ Hits 773 810 +37
- Misses 207 212 +5
- Partials 93 96 +3 ☔ View full report in Codecov by Sentry. |
290dd59
to
f5f41de
Compare
Thankyou for the contribution, however I have a concern about this. The OIDC spec has the users picture as a URL (string) in the If this is non standard then there should be an extension point that can be implemented and chosen, with (I would say) the only implementation in this plugin should be the standard picture claim, which can just store and return the URL. |
Thanks for the review. If the URL is the standard, let's use the URL to display the avatar. I will check then on my side how to get a URL based on the base64 data (maybe some keycloak extension to extract the thumbnail and upload it somewhere, then return the URL in the profile). I will update the PR harcodingly |
I've pushed 2 commits. One that remove the configuration for the picture field since it's standard on OpenId. The other one that change to direct link for the avatar. The URL is now stored as property <avatarImage>
<url>http://localhost:8083/realms/ci-local-dev/avatar/ab2a1093-db55-4b61-8711-08ac4c38252e</url>
</avatarImage> I confirm it work when the image is hosted on different domain (jenkins 8080, keycloak 8083) |
6149b12
to
e73813f
Compare
I rebased the 4 commits |
e73813f
to
f8b3750
Compare
Fixed conflicts due to Junit5 migration and squashed commits |
Signed-off-by: Valentin Delaye <[email protected]>
f8b3750
to
91ca44a
Compare
@jtnord Hi again, would you be able to take a look? It's now using standard picture claim |
} | ||
|
||
public String getDisplayName() { | ||
return "Openid Connect Avatar"; |
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.
return "Openid Connect Avatar"; | |
return "OpenID Connect Avatar"; |
@Override | ||
@NonNull | ||
public String getDisplayName() { | ||
return "Openid Connect Avatar"; |
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.
it is OpenID
not OpenId
or Openid
(the ID is for Identity Document not Id as in Identity).
(yes this plugin should have been called oidc-auth
but that ship sailed, but the user facing stuff should be correct)
return "Openid Connect Avatar"; | |
return "OpenID Connect Avatar"; |
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.
I will fix for the new code. However there are multiple occurence on the plugin
For example
OicSecurityRealm.DisplayName = Se connecter avec Openid Connect
OicSecurityRealm.ClientIdRequired = Le client id est requis.
OicSecurityRealm.ClientSecretRequired = Le client secret est obligatoire.
OicSecurityRealm.URLNotAOpenIdEnpoint = L'URL ne semble pas d\u00e9crire des terminaux OpenID Connect
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, I thought I had fixed them, but obviously I hadn't. filed #542 so I do not forget.
import java.util.logging.Logger; | ||
|
||
public class OicAvatarProperty extends UserProperty { | ||
private static final Logger LOGGER = Logger.getLogger(OicAvatarProperty.class.getName()); |
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.
unused logger
private static final Logger LOGGER = Logger.getLogger(OicAvatarProperty.class.getName()); |
OicAvatarProperty oicAvatarProperty = new OicAvatarProperty(avatarImage); | ||
user.addProperty(oicAvatarProperty); | ||
} else { | ||
LOGGER.finest("No avatar URL found"); |
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.
Would It be useful to know which user this was for?
Also should this not remove the property (e.g. if someone deletes there picture from the profile, we would continue to show it?)
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.
Good point
@@ -834,6 +858,14 @@ private static void assertTestUserEmail(User user) { | |||
user.getProperty(Mailer.UserProperty.class).getAddress()); | |||
} | |||
|
|||
private static void assertTestAvatar(User user, WireMockRule wireMockRule) { | |||
String expectedAvatarUrl = "http://localhost:%s/my-avatar.png".formatted(wireMockRule.port()); |
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.
WiremockRule.baseUrl()
?
try { | ||
String avatarUrl = determineStringField(avatarFieldExpr, idToken, userInfo); | ||
if (avatarUrl != null) { | ||
LOGGER.finest("Avatar url is: " + avatarUrl); |
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.
This does string concatenation and then in most cases throws the result away.
Better to use parameterized logging or a supplier.
Additionally, would it be useful to know which user this was for?
(untested)
LOGGER.finest("Avatar url is: " + avatarUrl); | |
LOGGER.finest(() -> {"Avatar for user `" + user.getId() + "` url is: " + avatarUrl }); |
LOGGER.finest("No avatar URL found"); | ||
} | ||
|
||
} catch (Exception e) { |
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.
is it still valid to have this in a try/catch now we are not downloading, / decrypting the picture?
assertEquals(expectedAvatarUrl, avatarProperty.getAvatarUrl(), "Avatar url should be " + expectedAvatarUrl); | ||
assertEquals("Openid Connect Avatar", avatarProperty.getDisplayName()); | ||
assertNull(avatarProperty.getIconFileName(), "Icon filename must be null"); |
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.
should this not check the AvatarResolver also?
e.g. (untested)
assertEquals(expectedAvatarUrl, avatarProperty.getAvatarUrl(), "Avatar url should be " + expectedAvatarUrl); | |
assertEquals("Openid Connect Avatar", avatarProperty.getDisplayName()); | |
assertNull(avatarProperty.getIconFileName(), "Icon filename must be null"); | |
assertEquals(expectedAvatarUrl, avatarProperty.getAvatarUrl(), "Avatar url should be " + expectedAvatarUrl); | |
assertEquals("OpenID Connect Avatar", avatarProperty.getDisplayName()); | |
assertNull(avatarProperty.getIconFileName(), "Icon filename must be null"); | |
String urlViaAvatarResolver = UserAvatarResolver.resolve(user, "48x48"); | |
assertEquals(expectedAvatarUrl, urlViaAvatarResolver, "Avatar url should be " + expectedAvatarUrl); |
thanks for the reminder, I had reviewed it but forgot to submit it :( |
Fix for #512 (more details here)
Other known plugin that support avatar extension point
https://github.com/jenkinsci/avatar-plugin
https://github.com/jenkinsci/azure-ad-plugin
https://github.com/jenkinsci/gravatar-plugin
Testing done
There was some fixes on Jenkins 2.495 for avatar rendering. That's why it would look different
On 2.479.1 (this current plugin jenkins.version). This is was fixed by jenkinsci/jenkins#10180 which should be included on ~3 month LTS
On 2.495 this looks much better
Submitter checklist