OIDCUserManager { public Principal updateUser(IDTokenClaimsSet idToken, UserInfo userInfo) throws XWikiException, QueryException, OIDCException { checkAllowedGroups(userInfo); Map<String, String> formatMap = createFormatMap(idToken, userInfo); StringSubstitutor substitutor = new StringSubstitutor(new OIDCStringLookup(formatMap)); String formattedSubject = formatSubjec(substitutor); XWikiDocument userDocument = this.store.searchDocument(idToken.getIssuer().getValue(), formattedSubject); XWikiDocument modifiableDocument; boolean newUser; if (userDocument == null) { userDocument = getNewUserDocument(substitutor); newUser = true; modifiableDocument = userDocument; } else { newUser = false; modifiableDocument = userDocument.clone(); } XWikiContext xcontext = this.xcontextProvider.get(); BaseClass userClass = xcontext.getWiki().getUserClass(xcontext); BaseObject userObject = modifiableDocument.getXObject(userClass.getDocumentReference(), true, xcontext); userObject.set("active", 1, xcontext); Address address = userInfo.getAddress(); if (address != null) { userObject.set("address", address.getFormatted(), xcontext); } if (userInfo.getEmailAddress() != null) { userObject.set("email", userInfo.getEmailAddress(), xcontext); } if (userInfo.getFamilyName() != null) { userObject.set("last_name", userInfo.getFamilyName(), xcontext); } if (userInfo.getGivenName() != null) { userObject.set("first_name", userInfo.getGivenName(), xcontext); } if (userInfo.getPhoneNumber() != null) { userObject.set("phone", userInfo.getPhoneNumber(), xcontext); } if (userInfo.getLocale() != null) { userObject.set("default_language", Locale.forLanguageTag(userInfo.getLocale()).toString(), xcontext); } if (userInfo.getZoneinfo() != null) { userObject.set("timezone", userInfo.getZoneinfo(), xcontext); } if (userInfo.getWebsite() != null) { userObject.set("blog", userInfo.getWebsite().toString(), xcontext); } if (userInfo.getPicture() != null) { try { String filename = FilenameUtils.getName(userInfo.getPicture().toString()); URLConnection connection = userInfo.getPicture().toURL().openConnection(); connection.setRequestProperty("User-Agent", this.getClass().getPackage().getImplementationTitle() + '/' + this.getClass().getPackage().getImplementationVersion()); try (InputStream content = connection.getInputStream()) { modifiableDocument.setAttachment(filename, content, xcontext); } userObject.set("avatar", filename, xcontext); } catch (IOException e) { this.logger.warn("Failed to get user avatar from URL [{}]: {}", userInfo.getPicture(), ExceptionUtils.getRootCauseMessage(e)); } } updateXWikiClaims(modifiableDocument, userClass, userObject, userInfo, xcontext); this.store.updateOIDCUser(modifiableDocument, idToken.getIssuer().getValue(), formattedSubject); updateUserMapping(modifiableDocument, userClass, userObject, xcontext, substitutor); OIDCUserEventData eventData = new OIDCUserEventData(new NimbusOIDCIdToken(idToken), new NimbusOIDCUserInfo(userInfo)); this.observation.notify(new OIDCUserUpdating(modifiableDocument.getDocumentReference()), modifiableDocument, eventData); boolean userUpdated = false; if (newUser || userDocument.apply(modifiableDocument)) { String comment; if (newUser) { comment = "Create user from OpenID Connect"; } else { comment = "Update user from OpenID Connect"; } xcontext.getWiki().saveDocument(userDocument, comment, xcontext); if (newUser) { xcontext.getWiki().setUserDefaultGroup(userDocument.getFullName(), xcontext); } userUpdated = true; } if (this.configuration.isGroupSync()) { userUpdated = updateGroupMembership(userInfo, userDocument, xcontext); } if (userUpdated) { this.observation.notify(new OIDCUserUpdated(userDocument.getDocumentReference()), userDocument, eventData); } return new SimplePrincipal(userDocument.getPrefixedFullName()); }  void updateUserInfoAsync(); void checkUpdateUserInfo(); Principal updateUserInfo(BearerAccessToken accessToken); Principal updateUserInfo(URI userInfoEndpoint, IDTokenClaimsSet idToken, BearerAccessToken accessToken); Principal updateUser(IDTokenClaimsSet idToken, UserInfo userInfo); Boolean syncXWikiGroupsMembership(String xwikiUserName, List<String> providerGroups, XWikiContext context); void logout();  }
@Test public void updateUserInfoWithGroupSyncWithDefaultGroupsClaim() throws XWikiException, QueryException, OIDCException, ComponentLookupException { Issuer issuer = new Issuer("http: Subject subject = new Subject("subject"); IDTokenClaimsSet idToken = new IDTokenClaimsSet(issuer, subject, Collections.emptyList(), new Date(), new Date()); UserInfo userInfo = new UserInfo(subject); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_USERINFOCLAIMS, ListUtils.sum(OIDCClientConfiguration.DEFAULT_USERINFOCLAIMS, Arrays.asList(OIDCClientConfiguration.DEFAULT_GROUPSCLAIM))); userInfo.setClaim(OIDCClientConfiguration.DEFAULT_GROUPSCLAIM, Arrays.asList("pgroup1", "pgroup2")); Principal principal = this.manager.updateUser(idToken, userInfo); assertEquals("xwiki:XWiki.issuer-subject", principal.getName()); XWikiDocument userDocument = this.oldcore.getSpyXWiki().getDocument( new DocumentReference(this.oldcore.getXWikiContext().getWikiId(), "XWiki", "issuer-subject"), this.oldcore.getXWikiContext()); assertFalse(userDocument.isNew()); BaseObject userObject = userDocument .getXObject(new DocumentReference(this.oldcore.getXWikiContext().getWikiId(), "XWiki", "XWikiUsers")); assertNotNull(userObject); OIDCUser oidcObject = new OIDCUser(userDocument.getXObject(this.oidcClassReference)); assertNotNull(oidcObject); assertEquals("http: assertEquals("subject", oidcObject.getSubject()); assertTrue(groupContains(this.pgroup1Reference, userDocument.getFullName())); assertTrue(groupContains(this.pgroup2Reference, userDocument.getFullName())); }
@Test public void updateUserInfoWithGroupSyncWithoutMapping() throws XWikiException, QueryException, OIDCException, ComponentLookupException { this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM, "groupclaim"); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_USERINFOCLAIMS, ListUtils.sum(OIDCClientConfiguration.DEFAULT_USERINFOCLAIMS, Arrays.asList( this.oldcore.getConfigurationSource().<String>getProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM)))); Issuer issuer = new Issuer("http: Subject subject = new Subject("subject"); IDTokenClaimsSet idToken = new IDTokenClaimsSet(issuer, subject, Collections.emptyList(), new Date(), new Date()); UserInfo userInfo = new UserInfo(subject); userInfo.setClaim("groupclaim", Arrays.asList("pgroup1", "pgroup2")); String userFullName = "XWiki.issuer-subject"; when(this.oldcore.getMockGroupService().getAllGroupsNamesForMember(userFullName, 0, 0, this.oldcore.getXWikiContext())).thenReturn(Arrays.asList("XWiki.existinggroup")); addMember(this.existinggroupReference, "XWiki.issuer-subject"); assertFalse(groupContains(this.group1Reference, userFullName)); assertFalse(groupContains(this.group2Reference, userFullName)); assertTrue(groupContains(this.existinggroupReference, userFullName)); Principal principal = this.manager.updateUser(idToken, userInfo); assertEquals("xwiki:XWiki.issuer-subject", principal.getName()); XWikiDocument userDocument = this.oldcore.getSpyXWiki().getDocument( new DocumentReference(this.oldcore.getXWikiContext().getWikiId(), "XWiki", "issuer-subject"), this.oldcore.getXWikiContext()); assertFalse(userDocument.isNew()); BaseObject userObject = userDocument .getXObject(new DocumentReference(this.oldcore.getXWikiContext().getWikiId(), "XWiki", "XWikiUsers")); assertNotNull(userObject); OIDCUser oidcObject = new OIDCUser(userDocument.getXObject(this.oidcClassReference)); assertNotNull(oidcObject); assertEquals("http: assertEquals("subject", oidcObject.getSubject()); assertTrue(groupContains(this.pgroup1Reference, userDocument.getFullName())); assertTrue(groupContains(this.pgroup2Reference, userDocument.getFullName())); assertFalse(groupContains(this.existinggroupReference, userDocument.getFullName())); }
@Test public void updateUserInfoWithGroupSyncWithMapping() throws XWikiException, QueryException, OIDCException, ComponentLookupException { this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_MAPPING, Arrays.asList("group1=pgroup1", "group1=pgroup2", "XWiki.group2=pgroup2", "existinggroup=othergroup")); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM, "groupclaim"); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_USERINFOCLAIMS, ListUtils.sum(OIDCClientConfiguration.DEFAULT_USERINFOCLAIMS, Arrays.asList( this.oldcore.getConfigurationSource().<String>getProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM)))); Issuer issuer = new Issuer("http: Subject subject = new Subject("subject"); IDTokenClaimsSet idToken = new IDTokenClaimsSet(issuer, subject, Collections.emptyList(), new Date(), new Date()); UserInfo userInfo = new UserInfo(subject); userInfo.setClaim("groupclaim", Arrays.asList("pgroup1", "pgroup2")); String userFullName = "XWiki.issuer-subject"; when(this.oldcore.getMockGroupService().getAllGroupsNamesForMember(userFullName, 0, 0, this.oldcore.getXWikiContext())).thenReturn(Arrays.asList("XWiki.existinggroup")); addMember(this.existinggroupReference, "XWiki.issuer-subject"); assertFalse(groupContains(this.group1Reference, userFullName)); assertFalse(groupContains(this.group2Reference, userFullName)); assertTrue(groupContains(this.existinggroupReference, userFullName)); Principal principal = this.manager.updateUser(idToken, userInfo); assertEquals("xwiki:XWiki.issuer-subject", principal.getName()); XWikiDocument userDocument = this.oldcore.getSpyXWiki().getDocument( new DocumentReference(this.oldcore.getXWikiContext().getWikiId(), "XWiki", "issuer-subject"), this.oldcore.getXWikiContext()); assertFalse(userDocument.isNew()); BaseObject userObject = userDocument .getXObject(new DocumentReference(this.oldcore.getXWikiContext().getWikiId(), "XWiki", "XWikiUsers")); assertNotNull(userObject); OIDCUser oidcObject = new OIDCUser(userDocument.getXObject(this.oidcClassReference)); assertNotNull(oidcObject); assertEquals("http: assertEquals("subject", oidcObject.getSubject()); assertTrue(groupContains(this.group1Reference, userDocument.getFullName())); assertTrue(groupContains(this.group2Reference, userDocument.getFullName())); assertFalse(groupContains(this.existinggroupReference, userDocument.getFullName())); }
@Test public void updateUserInfoWithCustomNameAndIdPattern() throws XWikiException, QueryException, OIDCException, ComponentLookupException, URISyntaxException { this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_USER_NAMEFORMATER, "custom-${oidc.user.mail}-${oidc.user.mail.upperCase}-${oidc.user.mail.clean.upperCase}"); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_USER_SUBJECTFORMATER, "custom-${oidc.user.mail}-${oidc.user.mail.upperCase}-${oidc.user.mail.clean.upperCase}"); Issuer issuer = new Issuer("http: Subject subject = new Subject("subject"); IDTokenClaimsSet idToken = new IDTokenClaimsSet(issuer, subject, Collections.emptyList(), new Date(), new Date()); UserInfo userInfo = new UserInfo(subject); Address address = new Address(); address.setFormatted("address"); userInfo.setPreferredUsername("preferredUserName"); userInfo.setAddress(address); userInfo.setEmailAddress("mail@domain.com"); userInfo.setFamilyName("familyName"); userInfo.setGivenName("givenName"); userInfo.setPhoneNumber("phoneNumber"); userInfo.setLocale("fr"); userInfo.setZoneinfo("timezone"); userInfo.setWebsite(new URI("http: Principal principal = this.manager.updateUser(idToken, userInfo); assertEquals("xwiki:XWiki.custom-mail@domain\\.com-MAIL@DOMAIN\\.COM-MAILDOMAINCOM", principal.getName()); XWikiDocument userDocument = this.oldcore.getSpyXWiki().getDocument(new DocumentReference(this.oldcore.getXWikiContext().getWikiId(), "XWiki", "custom-mail@domain.com-MAIL@DOMAIN.COM-MAILDOMAINCOM"), this.oldcore.getXWikiContext()); assertFalse(userDocument.isNew()); BaseObject userObject = userDocument .getXObject(new DocumentReference(this.oldcore.getXWikiContext().getWikiId(), "XWiki", "XWikiUsers")); assertNotNull(userObject); assertEquals("address", userObject.getStringValue("address")); assertEquals("mail@domain.com", userObject.getStringValue("email")); assertEquals("familyName", userObject.getStringValue("last_name")); assertEquals("givenName", userObject.getStringValue("first_name")); assertEquals("phoneNumber", userObject.getStringValue("phone")); OIDCUser oidcObject = new OIDCUser(userDocument.getXObject(this.oidcClassReference)); assertNotNull(oidcObject); assertEquals("http: assertEquals("custom-mail@domain.com-MAIL@DOMAIN.COM-MAILDOMAINCOM", oidcObject.getSubject()); }
@Test public void updateUserInfoWithAllowedGroup() throws XWikiException, QueryException, OIDCException, ComponentLookupException { this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_ALLOWED, Arrays.asList("pgroup1", "pgroup2")); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM, "groupclaim"); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_USERINFOCLAIMS, ListUtils.sum(OIDCClientConfiguration.DEFAULT_USERINFOCLAIMS, Arrays.asList( this.oldcore.getConfigurationSource().<String>getProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM)))); Issuer issuer = new Issuer("http: Subject subject = new Subject("subject"); IDTokenClaimsSet idToken = new IDTokenClaimsSet(issuer, subject, Collections.emptyList(), new Date(), new Date()); UserInfo userInfo = new UserInfo(subject); userInfo.setClaim("groupclaim", Arrays.asList("pgroup1", "pgroup3")); Principal principal = this.manager.updateUser(idToken, userInfo); assertNotNull(principal); }
@Test public void updateUserInfoWithNotAllowedGroup() throws XWikiException, QueryException, OIDCException, ComponentLookupException { this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_ALLOWED, Arrays.asList("pgroup1")); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM, "groupclaim"); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_USERINFOCLAIMS, ListUtils.sum(OIDCClientConfiguration.DEFAULT_USERINFOCLAIMS, Arrays.asList( this.oldcore.getConfigurationSource().<String>getProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM)))); Issuer issuer = new Issuer("http: Subject subject = new Subject("subject"); IDTokenClaimsSet idToken = new IDTokenClaimsSet(issuer, subject, Collections.emptyList(), new Date(), new Date()); UserInfo userInfo = new UserInfo(subject); userInfo.setClaim("groupclaim", Arrays.asList("pgroup2", "pgroup3")); assertThrows(OIDCException.class, () -> this.manager.updateUser(idToken, userInfo)); }
@Test public void updateUserInfoWithForbiddenGroup() throws XWikiException, QueryException, OIDCException, ComponentLookupException { this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_FORBIDDEN, Arrays.asList("pgroup1", "pgroup2")); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM, "groupclaim"); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_USERINFOCLAIMS, ListUtils.sum(OIDCClientConfiguration.DEFAULT_USERINFOCLAIMS, Arrays.asList( this.oldcore.getConfigurationSource().<String>getProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM)))); Issuer issuer = new Issuer("http: Subject subject = new Subject("subject"); IDTokenClaimsSet idToken = new IDTokenClaimsSet(issuer, subject, Collections.emptyList(), new Date(), new Date()); UserInfo userInfo = new UserInfo(subject); userInfo.setClaim("groupclaim", Arrays.asList("pgroup1", "pgroup3")); assertThrows(OIDCException.class, () -> this.manager.updateUser(idToken, userInfo)); }
@Test public void updateUserInfoWithNotForbiddenGroup() throws XWikiException, QueryException, OIDCException, ComponentLookupException { this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_FORBIDDEN, Arrays.asList("pgroup1")); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM, "groupclaim"); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_USERINFOCLAIMS, ListUtils.sum(OIDCClientConfiguration.DEFAULT_USERINFOCLAIMS, Arrays.asList( this.oldcore.getConfigurationSource().<String>getProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM)))); Issuer issuer = new Issuer("http: Subject subject = new Subject("subject"); IDTokenClaimsSet idToken = new IDTokenClaimsSet(issuer, subject, Collections.emptyList(), new Date(), new Date()); UserInfo userInfo = new UserInfo(subject); userInfo.setClaim("groupclaim", Arrays.asList("pgroup2", "pgroup3")); Principal principal = this.manager.updateUser(idToken, userInfo); assertNotNull(principal); }
@Test public void updateUserInfoWithAllowedAndForbiddenGroup() throws XWikiException, QueryException, OIDCException, ComponentLookupException { this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_ALLOWED, Arrays.asList("pgroup1", "pgroup2")); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_FORBIDDEN, Arrays.asList("pgroup1", "pgroup2")); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_USERINFOCLAIMS, ListUtils.sum(OIDCClientConfiguration.DEFAULT_USERINFOCLAIMS, Arrays.asList( this.oldcore.getConfigurationSource().<String>getProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM)))); Issuer issuer = new Issuer("http: Subject subject = new Subject("subject"); IDTokenClaimsSet idToken = new IDTokenClaimsSet(issuer, subject, Collections.emptyList(), new Date(), new Date()); UserInfo userInfo = new UserInfo(subject); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM, "groupclaim"); userInfo.setClaim("groupclaim", Arrays.asList("pgroup1", "pgroup3")); assertNotNull(this.manager.updateUser(idToken, userInfo)); userInfo.setClaim("groupclaim", Arrays.asList("otherpgroup1", "otherpgroup3")); assertThrows(OIDCException.class, () -> this.manager.updateUser(idToken, userInfo), "The user is not allowed to authenticate because it's not a member of the following groups: [pgroup1, pgroup2]"); this.oldcore.getConfigurationSource().setProperty(OIDCClientConfiguration.PROP_GROUPS_CLAIM, "custom.customgroupclaim"); userInfo.setClaim("custom", Collections.singletonMap("customgroupclaim", Arrays.asList("pgroup1", "pgroup3"))); assertNotNull(this.manager.updateUser(idToken, userInfo)); userInfo.setClaim("custom", Collections.singletonMap("customgroupclaim", Arrays.asList("otherpgroup1", "otherpgroup3"))); assertThrows(OIDCException.class, () -> this.manager.updateUser(idToken, userInfo), "The user is not allowed to authenticate because it's not a member of the following groups: [pgroup1, pgroup2]"); }