Skip to content

Commit

Permalink
Migrate users with linked accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
oharsta committed Oct 11, 2023
1 parent cbd8edb commit af866ba
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 35 deletions.
24 changes: 12 additions & 12 deletions myconext-gui/src/locale/nl.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ I18n.translations.nl = {
},
start: {
hi: "Hi {{name}}!",
manage: "Beheer jouw persoonlijke informatie, jouw privacy, en de beveiliging van jouw eduID account.",
manage: "Beheer je persoonlijke informatie, je privacy, en de beveiliging van je eduID account.",
app: {
title: "Are you studying in NL? Connect your institution!",
infoBold: "When you study in the Netherlands ",
infoPart: "and you want to use eduID to login to educational services, we need to be sure it's you and not someone impersonating you.",
requirements: "You must therefore add the following information to your eduID",
validatedName: "Validation of your full name by a third party",
proofStudent: "Proof of being a student",
institution: "Your current institution",
connect: "Connect your school institution"
title: "Studeer je in NL? Koppel je instelling!",
infoBold: "Als je studeert in Nederland ",
infoPart: "en je wilt eduID gebruiken om in te loogen op onderwijsdiensten, dan willen we zekerheid over je identiteit.",
requirements: "Daarvoor kan je de volgende informatie toevoegen aan de eduID account",
validatedName: "Validatie van je volledige naam bij een instelling",
proofStudent: "Bewijs dat je een student bent",
institution: "Je huidige instelling",
connect: "Koppel je onderwijsinstelling"
}
},
header: {
Expand Down Expand Up @@ -81,9 +81,9 @@ I18n.translations.nl = {
remove: "Verwijder",
atInstitution: "Bij {{name}}",
studentRole: "Student",
preferInstitution: "Prefer institution",
preferredInstitutionConfirmation: "Do you want to use the information received from {{name}} to be the default information to share with services?",
preferred: "{{name}] is now your preferred source of information",
preferInstitution: "Voorkeursinstelling",
preferredInstitutionConfirmation: "Wil je de informatie die we van {{name}} ontvangen, gebruiken als standaardinformatie om met diensten te delen?",
preferred: "{{name}] is nu de bron van je persoonsinformatie",
expired: "Verlopen"
},
eppnAlreadyLinked: {
Expand Down
2 changes: 1 addition & 1 deletion myconext-gui/src/routes/PersonalInfo.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
const refresh = () => {
sortedAccounts = ($user.linkedAccounts || []).sort((a, b) => b.createdAt - a.createdAt);
const validLinkedAccounts = sortedAccounts.filter(account => !hasExpired(account));
const linkedAccount = validLinkedAccounts.find(account => account.preferred) || sortedAccounts[0];
const linkedAccount = validLinkedAccounts.find(account => account.preferred) || validLinkedAccounts[0];
if (isEmpty(linkedAccount) || isEmpty(linkedAccount.givenName) || isEmpty(linkedAccount.familyName)) {
preferredAccount = null;
} else {
Expand Down
3 changes: 2 additions & 1 deletion myconext-gui/src/routes/Start.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import settingsSvg from "../icons/redesign/settings.svg";
import getApp from "../icons/redesign/undraw_Mobile_app_re_catg 1.svg";
import Button from "../components/Button.svelte";
import {isEmpty} from "../utils/utils";
</script>

<style lang="scss">
Expand Down Expand Up @@ -140,7 +141,7 @@
<h2>{I18n.t("start.hi", {name: $user.givenName})}</h2>
<p class="manage">{I18n.t("start.manage")}</p>
<div class="card-container">
{#if !$user.loginOptions.includes("useApp") && (!$user.registration || !$user.registration.notificationType)}
{#if isEmpty($user.linkedAccounts)}
<div class="info-container">
<h4>{I18n.t("start.app.title")}</h4>
<div class="content-section">
Expand Down
28 changes: 24 additions & 4 deletions myconext-server/src/main/java/myconext/mongo/Migrations.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
import com.github.cloudyrock.mongock.ChangeSet;
import com.github.cloudyrock.mongock.driver.mongodb.springdata.v3.decorator.impl.MongockTemplate;
import myconext.manage.ServiceProviderResolver;
import myconext.model.EduID;
import myconext.model.PublicKeyCredentials;
import myconext.model.ServiceProvider;
import myconext.model.User;
import myconext.model.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.mongodb.core.query.Criteria;
Expand Down Expand Up @@ -140,6 +137,29 @@ public void deleteSessionAfterUserUpdate(MongockTemplate mongoTemplate) {
mongoTemplate.remove(new Query(), "sessions");
}

@SuppressWarnings("unchecked")
@ChangeSet(order = "007", id = "migrateUsers", author = "[email protected]")
public void migrateUsers(MongockTemplate mongoTemplate) {
Criteria criteria = Criteria.where("linkedAccounts").exists(true).type(JsonSchemaObject.Type.ARRAY).ne(new ArrayList<>());
List<User> users = mongoTemplate.find(new Query(criteria), User.class, "users");
users.forEach(user -> user.linkedAccountsSorted().stream()
.filter(LinkedAccount::areNamesValidated)
.findFirst()
.ifPresent(linkedAccount -> {
user.setGivenName(linkedAccount.getGivenName());
user.setFamilyName(linkedAccount.getFamilyName());
user.setChosenName(user.getGivenName());
linkedAccount.setPreferred(true);
mongoTemplate.save(user);
}));
}

@SuppressWarnings("unchecked")
@ChangeSet(order = "008", id = "deleteSessionAgain", author = "[email protected]")
public void deleteSessionAgain(MongockTemplate mongoTemplate) {
mongoTemplate.remove(new Query(), "sessions");
}

protected User mergeEduIDs(User user) {
List<EduID> eduIDS = user.getEduIDS();
//Make a copy to search in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -719,21 +719,9 @@ protected List<Attribute> attributes(User user, String requesterEntityId) {
List<LinkedAccount> linkedAccounts = safeSortedAffiliations(user);
String givenName = user.getGivenName();
String familyName = user.getFamilyName();
String chosenName = user.getChosenName();

//If one of the linkedAccounts is preferred then the validated names are already set on the user (backward compatibility)
if (!CollectionUtils.isEmpty(linkedAccounts) && linkedAccounts.stream().noneMatch(LinkedAccount::isPreferred)) {
Optional<LinkedAccount> first = linkedAccounts.stream()
.filter(LinkedAccount::areNamesValidated)
.findFirst();
//Can't use non-final variables in lambda
if (first.isPresent()) {
LinkedAccount linkedAccount = first.get();
givenName = linkedAccount.getGivenName();
familyName = linkedAccount.getFamilyName();
}
}

String displayName = String.format("%s %s", user.getChosenName(), familyName);
String displayName = String.format("%s %s", chosenName, familyName);
String commonName = String.format("%s %s", givenName, familyName);
String eppn = user.getEduPersonPrincipalName();
List<Attribute> attributes = new ArrayList(Arrays.asList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ public void accountLinkingRequiredNotNeeded() throws IOException {
@Test
public void accountLinkingWithValidatedNames() throws IOException {
User user = userRepository.findOneUserByEmail("[email protected]");
LinkedAccount linkedAccount = user.linkedAccountsSorted().get(0);

String authnContext = readFile("request_authn_context_validated_name.xml");
Response response = samlAuthnRequestResponseWithLoa(null, "relay", authnContext);
Expand All @@ -146,8 +145,8 @@ public void accountLinkingWithValidatedNames() throws IOException {
String samlResponse = samlResponse(magicLinkResponse);

assertTrue(samlResponse.contains(ACR.VALIDATE_NAMES));
assertTrue(samlResponse.contains(linkedAccount.getFamilyName()));
assertTrue(samlResponse.contains(linkedAccount.getGivenName()));
assertTrue(samlResponse.contains(user.getFamilyName()));
assertTrue(samlResponse.contains(user.getGivenName()));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ public void isUserVerifiedByInstitutionNoValidNamesAndExpired() {
@Test
public void attributes() {
User user = new User();
user.setGivenName("Mary");
user.setChosenName("Marrrry");
user.setFamilyName("Poppins");
List<LinkedAccount> linkedAccounts = Arrays.asList(
linkedAccount("John", "Doe", createdAt(15)),
linkedAccount("Mary", "Poppins", createdAt(10)),
Expand All @@ -127,9 +130,13 @@ public void attributes() {
List<Attribute> attributes = subject.attributes(user, "requesterEntityID");
String givenName = (String) attributes.stream().filter(attr -> attr.getName().equals("urn:mace:dir:attribute-def:givenName")).findFirst().get().getValues().get(0);
String familyName = (String) attributes.stream().filter(attr -> attr.getName().equals("urn:mace:dir:attribute-def:sn")).findFirst().get().getValues().get(0);
String displayName = (String) attributes.stream().filter(attr -> attr.getName().equals("urn:mace:dir:attribute-def:displayName")).findFirst().get().getValues().get(0);
String commonName = (String) attributes.stream().filter(attr -> attr.getName().equals("urn:mace:dir:attribute-def:commonName")).findFirst().get().getValues().get(0);

assertEquals("Mary", givenName);
assertEquals("Poppins", familyName);
assertEquals("Marrrry Poppins", displayName);
assertEquals("Mary Poppins", commonName);
}

private Date createdAt(int numberOfDaysInThePast) {
Expand Down

0 comments on commit af866ba

Please sign in to comment.