GitHub PullRequestReviewCommentEvent at 2014-06-04 22:50:28
Repository: Synapse-Repository-Services
Actor: john-hill
Payload: {"comment":{"url":"https://api.github.com/repos/Sage-Bionetworks/Synapse-Repository-Services/pulls/comments/13416115","id":13416115,"diff_hunk":"@@ -46,6 +101,340 @@ public boolean isAliasValid(String alias, AliasType type) {\n \t\t}\r\n \t}\r\n \t\r\n+\tpublic static String generateSignature(String payload) {\r\n+\t\ttry {\r\n+\t\t\tbyte[] secretKey = StackConfiguration.getEncryptionKey().getBytes(PARAMETER_CHARSET);\r\n+\t\t\tbyte[] signatureAsBytes = HMACUtils.generateHMACSHA1SignatureFromRawKey(payload, secretKey);\r\n+\t\t\treturn new String(signatureAsBytes, PARAMETER_CHARSET);\r\n+\t\t} catch (UnsupportedEncodingException e) {\r\n+\t\t\tthrow new RuntimeException(e);\r\n+\t\t}\r\n+\t}\r\n+\t\r\n+\tpublic static String generateSignatureForNewAccount(String firstName, String lastName, \r\n+\t\t\tString email, String timestamp, String domain) {\r\n+\t\treturn generateSignature(firstName+lastName+email+timestamp+domain);\r\n+\t}\r\n+\t\r\n+\t// note, this assumes that first name, last name and email are valid in 'user'\r\n+\tpublic static String createTokenForNewAccount(NewUser user, DomainType domain, Date now) {\r\n+\t\ttry {\r\n+\t\t\tStringBuilder sb = new StringBuilder();\r\n+\t\t\tString urlEncodedFirstName = URLEncoder.encode(user.getFirstName(), PARAMETER_CHARSET);\r\n+\t\t\tsb.append(EMAIL_VALIDATION_FIRST_NAME_PARAM+EQUALS+urlEncodedFirstName);\r\n+\t\t\tString urlEncodedLastName = URLEncoder.encode(user.getLastName(), PARAMETER_CHARSET);\r\n+\t\t\tsb.append(AMPERSAND+EMAIL_VALIDATION_LAST_NAME_PARAM+EQUALS+urlEncodedLastName);\r\n+\t\t\tString urlEncodedEmail = URLEncoder.encode(user.getEmail(), PARAMETER_CHARSET);\r\n+\t\t\tsb.append(AMPERSAND+EMAIL_VALIDATION_EMAIL_PARAM+EQUALS+urlEncodedEmail);\r\n+\t\t\tDateFormat df = new SimpleDateFormat(DATE_FORMAT_ISO8601);\r\n+\t\t\tString timestampString = df.format(now);\r\n+\t\t\tString urlEncodedTimeStampString = URLEncoder.encode(timestampString, PARAMETER_CHARSET);\r\n+\t\t\tsb.append(AMPERSAND+EMAIL_VALIDATION_TIME_STAMP_PARAM+EQUALS+urlEncodedTimeStampString);\r\n+\t\t\tString urlEncodedDomain = URLEncoder.encode(domain.name(), PARAMETER_CHARSET);\r\n+\t\t\tsb.append(AMPERSAND+EMAIL_VALIDATION_DOMAIN_PARAM+EQUALS+urlEncodedDomain);\r\n+\t\t\tString mac = generateSignatureForNewAccount(\r\n+\t\t\t\t\turlEncodedFirstName, urlEncodedLastName, urlEncodedEmail, \r\n+\t\t\t\t\turlEncodedTimeStampString, urlEncodedDomain);\r\n+\t\t\tsb.append(AMPERSAND+EMAIL_VALIDATION_SIGNATURE_PARAM+EQUALS+URLEncoder.encode(mac, PARAMETER_CHARSET));\r\n+\t\t\treturn sb.toString();\r\n+\t\t} catch (UnsupportedEncodingException e) {\r\n+\t\t\tthrow new RuntimeException(e);\r\n+\t\t}\r\n+\t}\r\n+\t\r\n+\t// returns the validated email address\r\n+\t// note, we pass the current time as a parameter to facilitate testing\r\n+\tpublic static String validateNewAccountToken(String token, Date now) {\r\n+\t\tString urlEncodedFirstName = null;\r\n+\t\tString urlEncodedLastName = null;\r\n+\t\tString urlEncodedEmail = null;\r\n+\t\tString urlEncodedTokenTimestampString = null;\r\n+\t\tString urlEncodedDomain = null;\r\n+\t\tString urlEncodedMac = null;\r\n+\t\tString[] requestParams = token.split(AMPERSAND);\r\n+\t\tfor (String param : requestParams) {\r\n+\t\t\tif (param.startsWith(EMAIL_VALIDATION_FIRST_NAME_PARAM+EQUALS)) {\r\n+\t\t\t\turlEncodedFirstName = param.substring((EMAIL_VALIDATION_FIRST_NAME_PARAM+EQUALS).length());\r\n+\t\t\t} else if (param.startsWith(EMAIL_VALIDATION_LAST_NAME_PARAM+EQUALS)) {\r\n+\t\t\t\turlEncodedLastName = param.substring((EMAIL_VALIDATION_LAST_NAME_PARAM+EQUALS).length());\r\n+\t\t\t} else if (param.startsWith(EMAIL_VALIDATION_EMAIL_PARAM+EQUALS)) {\r\n+\t\t\t\turlEncodedEmail = param.substring((EMAIL_VALIDATION_EMAIL_PARAM+EQUALS).length());\r\n+\t\t\t} else if (param.startsWith(EMAIL_VALIDATION_TIME_STAMP_PARAM+EQUALS)) {\r\n+\t\t\t\turlEncodedTokenTimestampString = param.substring((EMAIL_VALIDATION_TIME_STAMP_PARAM+EQUALS).length());\r\n+\t\t\t} else if (param.startsWith(EMAIL_VALIDATION_DOMAIN_PARAM+EQUALS)) {\r\n+\t\t\t\turlEncodedDomain = param.substring((EMAIL_VALIDATION_DOMAIN_PARAM+EQUALS).length());\r\n+\t\t\t} else if (param.startsWith(EMAIL_VALIDATION_SIGNATURE_PARAM+EQUALS)) {\r\n+\t\t\t\turlEncodedMac = param.substring((EMAIL_VALIDATION_SIGNATURE_PARAM+EQUALS).length());\r\n+\t\t\t}\r\n+\t\t}\r\n+\t\tif (urlEncodedFirstName==null) throw new IllegalArgumentException(\"first name is missing.\");\r\n+\t\tif (urlEncodedLastName==null) throw new IllegalArgumentException(\"last name is missing.\");\r\n+\t\tif (urlEncodedEmail==null) throw new IllegalArgumentException(\"email is missing.\");\r\n+\t\tif (urlEncodedTokenTimestampString==null) throw new IllegalArgumentException(\"time stamp is missing.\");\r\n+\t\tif (urlEncodedDomain==null) throw new IllegalArgumentException(\"domain is missing.\");\r\n+\t\tif (urlEncodedMac==null) throw new IllegalArgumentException(\"digital signature is missing.\");\r\n+\t\tString email;\r\n+\t\tString tokenTimestampString;\r\n+\t\ttry {\r\n+\t\t\temail = URLDecoder.decode(urlEncodedEmail, PARAMETER_CHARSET);\r\n+\t\t\ttokenTimestampString = URLDecoder.decode(urlEncodedTokenTimestampString, PARAMETER_CHARSET);\r\n+\t\t} catch (UnsupportedEncodingException e) {\r\n+\t\t\tthrow new RuntimeException(e);\r\n+\t\t}\r\n+\t\tDate tokenTimestamp;\r\n+\t\tDateFormat df = new SimpleDateFormat(DATE_FORMAT_ISO8601);\r\n+\t\ttry {\r\n+\t\t\ttokenTimestamp = df.parse(tokenTimestampString);\r\n+\t\t} catch (ParseException e) {\r\n+\t\t\tthrow new IllegalArgumentException(tokenTimestampString+\" is not a properly formatted time stamp\", e);\r\n+\t\t}\r\n+\t\tif (now.getTime()-tokenTimestamp.getTime()>EMAIL_VALIDATION_TIME_LIMIT_MILLIS) \r\n+\t\t\tthrow new IllegalArgumentException(\"Email validation link is out of date.\");\r\n+\t\tString mac = generateSignatureForNewAccount(\r\n+\t\t\t\turlEncodedFirstName, urlEncodedLastName, \r\n+\t\t\t\turlEncodedEmail, urlEncodedTokenTimestampString, urlEncodedDomain);\r\n+\t\tString newUrlEncodedMac;\r\n+\t\ttry {\r\n+\t\t\tnewUrlEncodedMac = URLEncoder.encode(mac, PARAMETER_CHARSET);\r\n+\t\t} catch(UnsupportedEncodingException e) {\r\n+\t\t\tthrow new RuntimeException(e);\r\n+\t\t}\r\n+\t\tif (!urlEncodedMac.equals(newUrlEncodedMac))\r\n+\t\t\tthrow new IllegalArgumentException(\"Invalid digital signature.\");\r\n+\t\treturn email;\r\n+\t}\r\n+\t\r\n+\tpublic static void validateSynapsePortalHost(String portalHost) {\r\n+\t\tportalHost = portalHost.toLowerCase().trim();\r\n+\t\tif (portalHost.endsWith(\"synapse.org\")) return;\r\n+\t\tif (portalHost.endsWith(\"sagebase.org\")) return;\r\n+\t\tif (portalHost.equals(\"localhost\")) return;\r\n+\t\tthrow new IllegalArgumentException(\"The provided parameter is not a valid Synapse endpoint.\");\r\n+\t}\r\n+\t\r\n+\t// will throw exception for invalid email, invalid endpoint, invalid domain, or an email which is already taken\r\n+\t@Override\r\n+\tpublic void newAccountEmailValidation(NewUser user, String portalEndpoint, DomainType domain) {\r\n+\t\tif (user.getFirstName()==null || user.getFirstName().length()==0) throw new IllegalArgumentException(\"first name required\");\r\n+\t\tif (user.getLastName()==null || user.getLastName().length()==0) throw new IllegalArgumentException(\"last name required\");\r\n+\t\tAliasEnum.USER_EMAIL.validateAlias(user.getEmail());\r\n+\t\t\r\n+\t\tif (domain.equals(DomainType.SYNAPSE) || domain.equals(DomainType.BRIDGE)) {\r\n+\t\t\tString token = createTokenForNewAccount(user, domain, new Date());\r\n+\t\t\tString urlString = portalEndpoint+token;\r\n+\t\t\tURL url = null;\r\n+\t\t\ttry {\r\n+\t\t\t\turl = new URL(urlString);\r\n+\t\t\t} catch (MalformedURLException e) {\r\n+\t\t\t\tthrow new IllegalArgumentException(\"The provided endpoint creates an invalid URL\");\r\n+\t\t\t}\r\n+\t\t\tvalidateSynapsePortalHost(url.getHost());\r\n+\t\t\t// is the email taken?\r\n+\t\t\tif (!principalAliasDAO.isAliasAvailable(user.getEmail())) {\r\n+\t\t\t\tthrow new NameConflictException(\"The email address provided is already used.\");\r\n+\t\t\t}\r\n+\t\t\t\r\n+\t\t\t// all requirements are met, so send the email\r\n+\t\t\tString domainString = WordUtils.capitalizeFully(domain.name());\r\n+\t\t\tString subject = \"Welcome to \" + domain + \"!\";\r\n+\t\t\tMap<String,String> fieldValues = new HashMap<String,String>();\r\n+\t\t\tfieldValues.put(EmailUtils.TEMPLATE_KEY_DISPLAY_NAME, user.getFirstName()+\" \"+user.getLastName());\r\n+\t\t\tfieldValues.put(EmailUtils.TEMPLATE_KEY_ORIGIN_CLIENT, domainString);\r\n+\t\t\tfieldValues.put(EmailUtils.TEMPLATE_KEY_WEB_LINK, urlString);\r\n+\t\t\tString messageBody = EmailUtils.readMailTemplate(\"message/CreateAccountTemplate.txt\", fieldValues);\r\n+\t\t\tSendEmailRequest sendEmailRequest = EmailUtils.createEmailRequest(user.getEmail(), subject, messageBody, false, null);\r\n+\t\t\tsesClient.sendEmail(sendEmailRequest);\r\n+\t\t} else {\r\n+\t\t\tthrow new IllegalArgumentException(\"Unexpected Domain: \"+domain);\r\n+\t\t}\r\n+\t}\r\n+\r\n+\t@Transactional(readOnly = false, propagation = Propagation.REQUIRED)\r\n+\t@Override\r\n+\tpublic Session createNewAccount(AccountSetupInfo accountSetupInfo, DomainType domain) throws NotFoundException {\r\n+\t\tString validatedEmail = validateNewAccountToken(accountSetupInfo.getEmailValidationToken(), new Date());\r\n+\r\n+\t\tNewUser newUser = new NewUser();\r\n+\t\tnewUser.setEmail(validatedEmail);\r\n+\t\tnewUser.setFirstName(accountSetupInfo.getFirstName());\r\n+\t\tnewUser.setLastName(accountSetupInfo.getLastName());\r\n+\t\tnewUser.setUserName(accountSetupInfo.getUsername());\r\n+\t\tlong newPrincipalId = userManager.createUser(newUser);\r\n+\t\t\r\n+\t\tauthManager.changePassword(newPrincipalId, accountSetupInfo.getPassword());\r\n+\t\treturn authManager.authenticate(newPrincipalId, accountSetupInfo.getPassword(), domain);\r\n+\t}\r\n+\r\n+\tpublic static String generateSignatureForAdditionalEmail(String userId, String email, String timestamp, String domain) {\r\n+\t\treturn generateSignature(userId+email+timestamp+domain);\r\n+\t}\r\n+\t\r\n+\tpublic static String createTokenForAdditionalEmail(Long userId, String email, DomainType domain, Date now) {\r\n+\t\ttry {\r\n+\t\t\tStringBuilder sb = new StringBuilder();\r\n+\t\t\tString urlEncodedUserId = URLEncoder.encode(userId.toString(), PARAMETER_CHARSET);\r\n+\t\t\tsb.append(EMAIL_VALIDATION_USER_ID_PARAM+EQUALS+urlEncodedUserId);\r\n+\t\t\tString urlEncodedEmail = URLEncoder.encode(email, PARAMETER_CHARSET);\r\n+\t\t\tsb.append(AMPERSAND+EMAIL_VALIDATION_EMAIL_PARAM+EQUALS+urlEncodedEmail);\r\n+\t\t\tDateFormat df = new SimpleDateFormat(DATE_FORMAT_ISO8601);\r\n+\t\t\tString timestampString = df.format(now);\r\n+\t\t\tString urlEncodedTimeStampString = URLEncoder.encode(timestampString, PARAMETER_CHARSET);\r\n+\t\t\tsb.append(AMPERSAND+EMAIL_VALIDATION_TIME_STAMP_PARAM+EQUALS+urlEncodedTimeStampString);\r\n+\t\t\tString urlEncodedDomain = URLEncoder.encode(domain.name(), PARAMETER_CHARSET);\r\n+\t\t\tsb.append(AMPERSAND+EMAIL_VALIDATION_DOMAIN_PARAM+EQUALS+urlEncodedDomain);\r\n+\t\t\tString mac = generateSignatureForAdditionalEmail(urlEncodedUserId, urlEncodedEmail, \r\n+\t\t\t\t\turlEncodedTimeStampString, urlEncodedDomain);\r\n+\t\t\tsb.append(AMPERSAND+EMAIL_VALIDATION_SIGNATURE_PARAM+EQUALS+URLEncoder.encode(mac, PARAMETER_CHARSET));\r\n+\t\t\treturn sb.toString();\r\n+\t\t} catch (UnsupportedEncodingException e) {\r\n+\t\t\tthrow new RuntimeException(e);\r\n+\t\t}\r\n+\t}\r\n+\t\r\n+\t// returns the validated email address\r\n+\t// note, we pass the current time as a parameter to facilitate testing\r\n+\tpublic static void validateAdditionalEmailToken(String token, Date now) {\r\n+\t\tString urlEncodedUserId = null;\r\n+\t\tString urlEncodedEmail = null;\r\n+\t\tString urlEncodedTimestampString = null;\r\n+\t\tString urlEncodedDomain = null;\r\n+\t\tString urlEncodedMac = null;\r\n+\t\tString[] requestParams = token.split(AMPERSAND);\r\n+\t\tfor (String param : requestParams) {\r\n+\t\t\tif (param.startsWith(EMAIL_VALIDATION_USER_ID_PARAM+EQUALS)) {\r\n+\t\t\t\turlEncodedUserId = param.substring((EMAIL_VALIDATION_USER_ID_PARAM+EQUALS).length());\r\n+\t\t\t} else if (param.startsWith(EMAIL_VALIDATION_EMAIL_PARAM+EQUALS)) {\r\n+\t\t\t\turlEncodedEmail = param.substring((EMAIL_VALIDATION_EMAIL_PARAM+EQUALS).length());\r\n+\t\t\t} else if (param.startsWith(EMAIL_VALIDATION_TIME_STAMP_PARAM+EQUALS)) {\r\n+\t\t\t\turlEncodedTimestampString = param.substring((EMAIL_VALIDATION_TIME_STAMP_PARAM+EQUALS).length());\r\n+\t\t\t} else if (param.startsWith(EMAIL_VALIDATION_DOMAIN_PARAM+EQUALS)) {\r\n+\t\t\t\turlEncodedDomain = param.substring((EMAIL_VALIDATION_DOMAIN_PARAM+EQUALS).length());\r\n+\t\t\t} else if (param.startsWith(EMAIL_VALIDATION_SIGNATURE_PARAM+EQUALS)) {\r\n+\t\t\t\turlEncodedMac = param.substring((EMAIL_VALIDATION_SIGNATURE_PARAM+EQUALS).length());\r\n+\t\t\t}\r\n+\t\t}\r\n+\t\tif (urlEncodedUserId==null) throw new IllegalArgumentException(\"userId is missing.\");\r\n+\t\tif (urlEncodedEmail==null) throw new IllegalArgumentException(\"email is missing.\");\r\n+\t\tif (urlEncodedTimestampString==null) throw new IllegalArgumentException(\"time stamp is missing.\");\r\n+\t\tif (urlEncodedDomain==null) throw new IllegalArgumentException(\"domain is missing.\");\r\n+\t\tif (urlEncodedMac==null) throw new IllegalArgumentException(\"digital signature is missing.\");\r\n+\t\tString tokenTimestampString;\r\n+\t\ttry {\r\n+\t\t\ttokenTimestampString = URLDecoder.decode(urlEncodedTimestampString, PARAMETER_CHARSET);\r\n+\t\t} catch (UnsupportedEncodingException e) {\r\n+\t\t\tthrow new RuntimeException(e);\r\n+\t\t}\r\n+\t\tDate tokenTimestamp;\r\n+\t\tDateFormat df = new SimpleDateFormat(DATE_FORMAT_ISO8601);\r\n+\t\ttry {\r\n+\t\t\ttokenTimestamp = df.parse(tokenTimestampString);\r\n+\t\t} catch (ParseException e) {\r\n+\t\t\tthrow new IllegalArgumentException(tokenTimestampString+\" is not a properly formatted time stamp\", e);\r\n+\t\t}\r\n+\t\tif (now.getTime()-tokenTimestamp.getTime()>EMAIL_VALIDATION_TIME_LIMIT_MILLIS) \r\n+\t\t\tthrow new IllegalArgumentException(\"Email validation link is out of date.\");\r\n+\t\tString mac = generateSignatureForAdditionalEmail(\r\n+\t\t\t\turlEncodedUserId, urlEncodedEmail, urlEncodedTimestampString, urlEncodedDomain);\r\n+\t\tString newUrlEncodedMac;\r\n+\t\ttry {\r\n+\t\t\tnewUrlEncodedMac = URLEncoder.encode(mac, PARAMETER_CHARSET);\r\n+\t\t} catch(UnsupportedEncodingException e) {\r\n+\t\t\tthrow new RuntimeException(e);\r\n+\t\t}\r\n+\t\tif (!urlEncodedMac.equals(newUrlEncodedMac))\r\n+\t\t\tthrow new IllegalArgumentException(\"Invalid digital signature.\");\r\n+\t}\r\n+\t\r\n+\t@Override\r\n+\tpublic void additionalEmailValidation(UserInfo userInfo, Username email,\r\n+\t\t\tString portalEndpoint, DomainType domain) throws NotFoundException {\r\n+\t\tif (userInfo.getId()==AuthorizationConstants.BOOTSTRAP_PRINCIPAL.ANONYMOUS_USER.getPrincipalId())\r\n+\t\t\tthrow new UnauthorizedException(\"Anonymous user may not add email address.\");\r\n+\t\tAliasEnum.USER_EMAIL.validateAlias(email.getEmail());\r\n+\t\t\r\n+\t\tif (domain.equals(DomainType.SYNAPSE) || domain.equals(DomainType.BRIDGE)) {\r\n+\t\t\tString token = createTokenForAdditionalEmail(userInfo.getId(), email.getEmail(), domain, new Date());\r\n+\t\t\tString urlString = portalEndpoint+token;\r\n+\t\t\tURL url = null;\r\n+\t\t\ttry {\r\n+\t\t\t\turl = new URL(urlString);\r\n+\t\t\t} catch (MalformedURLException e) {\r\n+\t\t\t\tthrow new IllegalArgumentException(\"The provided endpoint creates an invalid URL\");\r\n+\t\t\t}\r\n+\t\t\tvalidateSynapsePortalHost(url.getHost());\r\n+\t\t\t// is the email taken?\r\n+\t\t\tif (!principalAliasDAO.isAliasAvailable(email.getEmail())) {\r\n+\t\t\t\tthrow new NameConflictException(\"The email address provided is already used.\");\r\n+\t\t\t}\r\n+\t\t\t\r\n+\t\t\t// all requirements are met, so send the email\r\n+\t\t\tString subject = \"Request to add or change new email\";\r\n+\t\t\tMap<String,String> fieldValues = new HashMap<String,String>();\r\n+\t\t\tUserProfile userProfile = userProfileDAO.get(userInfo.getId().toString());\r\n+\t\t\tfieldValues.put(EmailUtils.TEMPLATE_KEY_DISPLAY_NAME, \r\n+\t\t\t\t\tuserProfile.getFirstName()+\" \"+userProfile.getLastName());\r\n+\t\t\tfieldValues.put(EmailUtils.TEMPLATE_KEY_WEB_LINK, urlString);\r\n+\t\t\tfieldValues.put(EmailUtils.TEMPLATE_KEY_EMAIL, email.getEmail());\r\n+\t\t\tfieldValues.put(EmailUtils.TEMPLATE_KEY_ORIGIN_CLIENT, domain.name());\r\n+\t\t\tfieldValues.put(EmailUtils.TEMPLATE_KEY_USERNAME, userProfile.getUserName());\r\n+\t\t\tString messageBody = EmailUtils.readMailTemplate(\"message/AdditionalEmailTemplate.txt\", fieldValues);\r\n+\t\t\tSendEmailRequest sendEmailRequest = EmailUtils.createEmailRequest(email.getEmail(), subject, messageBody, false, null);\r\n+\t\t\tsesClient.sendEmail(sendEmailRequest);\r\n+\t\t} else {\r\n+\t\t\tthrow new IllegalArgumentException(\"Unexpected Domain: \"+domain);\r\n+\t\t}\r\n+\t}\r\n+\r\n+\tpublic static String getParameterValueFromToken(String token, String paramName) {\r\n+\t\tString[] requestParams = token.split(AMPERSAND);\r\n+\t\tfor (String param : requestParams) {\r\n+\t\t\tif (param.startsWith(paramName+EQUALS)) {\r\n+\t\t\t\tString urlEncodedParamValue = param.substring((paramName+EQUALS).length());\r\n+\t\t\t\ttry {\r\n+\t\t\t\t\treturn URLDecoder.decode(urlEncodedParamValue, PARAMETER_CHARSET);\r\n+\t\t\t\t} catch (UnsupportedEncodingException e) {\r\n+\t\t\t\t\tthrow new RuntimeException(e);\r\n+\t\t\t\t}\r\n+\t\t\t}\r\n+\t\t}\r\n+\t\tthrow new IllegalArgumentException(\"token does not contain parameter \"+paramName);\r\n+\t}\r\n+\r\n+\t@Transactional(readOnly = false, propagation = Propagation.REQUIRED)\r\n+\t@Override\r\n+\tpublic void addEmail(UserInfo userInfo, AddEmailInfo addEmailInfo,\r\n+\t\t\tBoolean setAsNotificationEmail) throws NotFoundException {\r\n+\t\tString token = addEmailInfo.getEmailValidationToken();\r\n+\t\tvalidateAdditionalEmailToken(token, new Date());\r\n+\t\tString validatedEmail = getParameterValueFromToken(token, EMAIL_VALIDATION_EMAIL_PARAM);\r\n+\t\tString originalUserId = getParameterValueFromToken(token, EMAIL_VALIDATION_USER_ID_PARAM);\r\n+\t\tif (!originalUserId.equals(userInfo.getId().toString()))\r\n+\t\t\tthrow new IllegalArgumentException(\"Invalid token for userId \"+userInfo.getId());\r\n+\t\tPrincipalAlias alias = new PrincipalAlias();\r\n+\t\talias.setAlias(validatedEmail);\r\n+\t\talias.setPrincipalId(userInfo.getId());\r\n+\t\talias.setType(AliasType.USER_EMAIL);\r\n+\t\talias = principalAliasDAO.bindAliasToPrincipal(alias);\r\n+\t\tif (setAsNotificationEmail!=null && setAsNotificationEmail==true) notificationEmailDao.update(alias);\r\n+\t}\r\n+\r\n+\t@Transactional(readOnly = false, propagation = Propagation.REQUIRED)\r\n+\t@Override\r\n+\tpublic void removeEmail(UserInfo userInfo, String email) throws NotFoundException {\r\n+\t\tif (email.equals(notificationEmailDao.getNotificationEmailForPrincipal(userInfo.getId())))\r\n+\t\t\t\tthrow new IllegalArgumentException(\"To remove this email from your account, first establish a different notification address.\");\r\n+\t\tPrincipalAlias emailAlias = findAliasForEmail(userInfo.getId(), email);\r\n+\t\tprincipalAliasDAO.removeAliasFromPrincipal(userInfo.getId(), emailAlias.getAliasId());\r\n+\t}\r\n+\t\r\n+\tprivate PrincipalAlias findAliasForEmail(Long principalId, String email) throws NotFoundException {\r\n+\t\tList<PrincipalAlias> aliases = principalAliasDAO.listPrincipalAliases(principalId, AliasType.USER_EMAIL);\r","path":"services/repository-managers/src/main/java/org/sagebionetworks/repo/manager/principal/PrincipalManagerImpl.java","position":414,"original_position":414,"commit_id":"06e55812231587da7ec4603e6cbbbd3d1f7f7183","original_commit_id":"06e55812231587da7ec4603e6cbbbd3d1f7f7183","user":{"login":"john-hill","id":1728181,"avatar_url":"https://avatars.githubusercontent.com/u/1728181?","gravatar_id":"667f10b14da74fe1cadf58d8155ea3b4","url":"https://api.github.com/users/john-hill","html_url":"https://github.com/john-hill","followers_url":"https://api.github.com/users/john-hill/followers","following_url":"https://api.github.com/users/john-hill/following{/other_user}","gists_url":"https://api.github.com/users/john-hill/gists{/gist_id}","starred_url":"https://api.github.com/users/john-hill/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/john-hill/subscriptions","organizations_url":"https://api.github.com/users/john-hill/orgs","repos_url":"https://api.github.com/users/john-hill/repos","events_url":"https://api.github.com/users/john-hill/events{/privacy}","received_events_url":"https://api.github.com/users/john-hill/received_events","type":"User","site_admin":false},"body":"pass along to the DAO.","created_at":"2014-06-04T22:50:28Z","updated_at":"2014-06-04T22:50:28Z","html_url":"https://github.com/Sage-Bionetworks/Synapse-Repository-Services/pull/1335#discussion_r13416115","pull_request_url":"https://api.github.com/repos/Sage-Bionetworks/Synapse-Repository-Services/pulls/1335","_links":{"self":{"href":"https://api.github.com/repos/Sage-Bionetworks/Synapse-Repository-Services/pulls/comments/13416115"},"html":{"href":"https://github.com/Sage-Bionetworks/Synapse-Repository-Services/pull/1335#discussion_r13416115"},"pull_request":{"href":"https://api.github.com/repos/Sage-Bionetworks/Synapse-Repository-Services/pulls/1335"}}}}