From 09b7bbfc2d4b570c99273389a353e9bde7e5ed4b Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 23 Jan 2017 15:03:35 -0800 Subject: [PATCH 1/8] issue-1257 allowing account stores to be retrieved by organizationNameKey --- .../ExternalAccountStoreModelFactory.java | 59 +++++++++++++++++-- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/mvc/provider/ExternalAccountStoreModelFactory.java b/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/mvc/provider/ExternalAccountStoreModelFactory.java index 309211ecf1..a9ef5176b8 100644 --- a/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/mvc/provider/ExternalAccountStoreModelFactory.java +++ b/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/mvc/provider/ExternalAccountStoreModelFactory.java @@ -15,8 +15,8 @@ */ package com.stormpath.sdk.servlet.mvc.provider; +import com.stormpath.sdk.accountStoreMapping.AccountStoreMapping; import com.stormpath.sdk.application.Application; -import com.stormpath.sdk.application.ApplicationAccountStoreMapping; import com.stormpath.sdk.application.ApplicationAccountStoreMappingCriteria; import com.stormpath.sdk.application.ApplicationAccountStoreMappingList; import com.stormpath.sdk.application.ApplicationAccountStoreMappings; @@ -26,11 +26,14 @@ import com.stormpath.sdk.directory.AccountStoreVisitor; import com.stormpath.sdk.directory.Directory; import com.stormpath.sdk.group.Group; +import com.stormpath.sdk.lang.Strings; import com.stormpath.sdk.organization.Organization; +import com.stormpath.sdk.organization.OrganizationAccountStoreMappingList; import com.stormpath.sdk.provider.GoogleProvider; import com.stormpath.sdk.provider.OAuthProvider; import com.stormpath.sdk.provider.Provider; import com.stormpath.sdk.provider.saml.SamlProvider; +import com.stormpath.sdk.resource.CollectionResource; import com.stormpath.sdk.servlet.application.ApplicationResolver; import javax.servlet.http.HttpServletRequest; @@ -51,17 +54,25 @@ public class ExternalAccountStoreModelFactory implements AccountStoreModelFactor public List getAccountStores(HttpServletRequest request) { Application app = ApplicationResolver.INSTANCE.getApplication(request); + CollectionResource accountStoreMappings; - int pageSize = 100; //get as much as we can in a single request - ApplicationAccountStoreMappingCriteria criteria = ApplicationAccountStoreMappings.criteria().limitTo(pageSize); - ApplicationAccountStoreMappingList mappings = app.getAccountStoreMappings(criteria); + String onk = request.getParameter("organizationNameKey"); + if (Strings.hasText(onk)) { + accountStoreMappings = getOrganizationAccountStoreMappings(app, onk); + } else { + accountStoreMappings = getApplicationAccountStoreMappings(app); + } + + if (accountStoreMappings == null) { + return new ArrayList<>(); //maybe error if onk isn't found??? + } - final List accountStores = new ArrayList<>(mappings.getSize()); + final List accountStores = new ArrayList<>(accountStoreMappings.getSize()); AccountStoreModelVisitor visitor = new AccountStoreModelVisitor(accountStores, getAuthorizeBaseUri(request, app.getWebConfig())); - for (ApplicationAccountStoreMapping mapping : mappings) { + for (AccountStoreMapping mapping : accountStoreMappings) { final AccountStore accountStore = mapping.getAccountStore(); @@ -71,6 +82,42 @@ public List getAccountStores(HttpServletRequest request) { return visitor.getAccountStores(); } + private ApplicationAccountStoreMappingList getApplicationAccountStoreMappings(Application app) { + int pageSize = 100; //get as much as we can in a single request + ApplicationAccountStoreMappingCriteria criteria = ApplicationAccountStoreMappings.criteria().limitTo(pageSize); + return app.getAccountStoreMappings(criteria); + } + + private OrganizationAccountStoreMappingList getOrganizationAccountStoreMappings(Application app, final String nameKey) { + ApplicationAccountStoreMappingList accountStoreMappings = app.getAccountStoreMappings(); + + final Organization[] organization = new Organization[1]; + + for (final AccountStoreMapping accountStoreMapping : accountStoreMappings) { + AccountStore accountStore = accountStoreMapping.getAccountStore(); + accountStore.accept(new AccountStoreVisitor() { + @Override + public void visit(Group group) {} + + @Override + public void visit(Directory directory) {} + + @Override + public void visit(Organization org) { + if (org.getNameKey().equals(nameKey)) { + organization[0] = org; + } + } + }); + } + + if (organization[0] == null) { + return null; + } + + return organization[0].getAccountStoreMappings(); + } + @SuppressWarnings("WeakerAccess") // Want to allow overriding this method protected String getAuthorizeBaseUri(@SuppressWarnings("UnusedParameters") HttpServletRequest request, ApplicationWebConfig webConfig) { String authorizeBaseUri = null; From a95bb9d7ff0b1e7cbdd05b6923ac9609cddd481b Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 31 Jan 2017 11:53:29 -0800 Subject: [PATCH 2/8] issue-1257 fixing unit test --- ...ultCreateOAuthPasswordGrantAuthenticationAttemptTest.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/impl/src/test/groovy/com/stormpath/sdk/impl/oauth/DefaultCreateOAuthPasswordGrantAuthenticationAttemptTest.groovy b/impl/src/test/groovy/com/stormpath/sdk/impl/oauth/DefaultCreateOAuthPasswordGrantAuthenticationAttemptTest.groovy index b080ba0cfe..6d4af1aeb4 100644 --- a/impl/src/test/groovy/com/stormpath/sdk/impl/oauth/DefaultCreateOAuthPasswordGrantAuthenticationAttemptTest.groovy +++ b/impl/src/test/groovy/com/stormpath/sdk/impl/oauth/DefaultCreateOAuthPasswordGrantAuthenticationAttemptTest.groovy @@ -39,11 +39,12 @@ class DefaultCreateOAuthPasswordGrantAuthenticationAttemptTest { def propertyDescriptors = defaultCreateGrantAuthAttempt.getPropertyDescriptors() - assertEquals(propertyDescriptors.size(), 4) + assertEquals(propertyDescriptors.size(), 5) assertTrue(propertyDescriptors.get("username") instanceof StringProperty) assertTrue(propertyDescriptors.get("password") instanceof StringProperty) assertTrue(propertyDescriptors.get("accountStore") instanceof StringProperty) + assertTrue(propertyDescriptors.get("organizationNameKey") instanceof StringProperty) assertTrue(propertyDescriptors.get("grant_type") instanceof StringProperty) } From 5ddd61ac1064e35e28bd30e417f322b0e1452eaa Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 3 Feb 2017 10:48:12 -0800 Subject: [PATCH 3/8] issue-1257 adding organizationNameKey parameter when creating an account --- .../sdk/account/CreateAccountRequest.java | 18 ++++++++++++++++++ .../account/CreateAccountRequestBuilder.java | 7 +++++++ .../account/DefaultCreateAccountRequest.java | 15 ++++++++++++++- .../DefaultCreateAccountRequestBuilder.java | 9 ++++++++- .../impl/application/DefaultApplication.java | 4 ++++ 5 files changed, 51 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/com/stormpath/sdk/account/CreateAccountRequest.java b/api/src/main/java/com/stormpath/sdk/account/CreateAccountRequest.java index f0eb86b4d8..1bfad71262 100644 --- a/api/src/main/java/com/stormpath/sdk/account/CreateAccountRequest.java +++ b/api/src/main/java/com/stormpath/sdk/account/CreateAccountRequest.java @@ -111,4 +111,22 @@ public interface CreateAccountRequest { */ AccountOptions getAccountOptions() throws IllegalStateException; + /** + * Returns {@code true} if the request has specified an organizationNameKey + * + * @return {@code true} if the request has specified an organizationNameKey + * + * @since 1.6.0 + */ + boolean isOrganizationNameKeySpecified(); + + /** + * Returns the organizationNameKey to be used in the CreateAccountRequest + * + * @return organizationNameKey to be used in the CreateAccountRequest + * + * @since 1.6.0 + */ + String getOrganizationNameKey(); + } diff --git a/api/src/main/java/com/stormpath/sdk/account/CreateAccountRequestBuilder.java b/api/src/main/java/com/stormpath/sdk/account/CreateAccountRequestBuilder.java index 6d6c4e507d..69f58b5408 100644 --- a/api/src/main/java/com/stormpath/sdk/account/CreateAccountRequestBuilder.java +++ b/api/src/main/java/com/stormpath/sdk/account/CreateAccountRequestBuilder.java @@ -62,6 +62,13 @@ public interface CreateAccountRequestBuilder { */ CreateAccountRequestBuilder withResponseOptions(AccountOptions options) throws IllegalArgumentException; + /** + * Ensures that the account will be created in the organization specified (given that it is mapped to the Application) + * + * @return the builder instance for method chaining. + */ + CreateAccountRequestBuilder withOrganizationNameKey(String organizationNameKey) throws IllegalArgumentException; + /** * Creates a new {@code CreateAccountRequest} instance based on the current builder state. * diff --git a/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultCreateAccountRequest.java b/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultCreateAccountRequest.java index ed93b5ad13..5e86c5a7c9 100644 --- a/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultCreateAccountRequest.java +++ b/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultCreateAccountRequest.java @@ -32,13 +32,16 @@ public class DefaultCreateAccountRequest implements CreateAccountRequest { private final AccountOptions options; + private final String organizationNameKey; + private PasswordFormat passwordFormat; - public DefaultCreateAccountRequest(Account account, Boolean registrationWorkflowEnabled, AccountOptions options) { + public DefaultCreateAccountRequest(Account account, Boolean registrationWorkflowEnabled, AccountOptions options, String organizationNameKey) { Assert.notNull(account, "Account cannot be null."); this.account = account; this.registrationWorkflowEnabled = registrationWorkflowEnabled; this.options = options; + this.organizationNameKey = organizationNameKey; } public Account getAccount() { @@ -88,4 +91,14 @@ public AccountOptions getAccountOptions() { } return this.options; } + + @Override + public boolean isOrganizationNameKeySpecified() { + return this.organizationNameKey != null; + } + + @Override + public String getOrganizationNameKey() { + return organizationNameKey; + } } diff --git a/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultCreateAccountRequestBuilder.java b/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultCreateAccountRequestBuilder.java index 53488b34cc..165de41cb9 100644 --- a/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultCreateAccountRequestBuilder.java +++ b/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultCreateAccountRequestBuilder.java @@ -27,6 +27,7 @@ public class DefaultCreateAccountRequestBuilder implements CreateAccountRequestB private Boolean registrationWorkflowEnabled; private PasswordFormat passwordFormat; private AccountOptions options; + private String organizationNameKey; public DefaultCreateAccountRequestBuilder(Account account) { Assert.notNull(account, "Account cannot be null."); @@ -56,8 +57,14 @@ public CreateAccountRequestBuilder withResponseOptions(AccountOptions options) { return this; } + @Override + public CreateAccountRequestBuilder withOrganizationNameKey(String organizationNameKey) throws IllegalArgumentException { + this.organizationNameKey = organizationNameKey; + return this; + } + @Override public CreateAccountRequest build() { - return new DefaultCreateAccountRequest(this.account, this.registrationWorkflowEnabled, this.options).setPasswordFormat(this.passwordFormat); + return new DefaultCreateAccountRequest(this.account, this.registrationWorkflowEnabled, this.options, this.organizationNameKey).setPasswordFormat(this.passwordFormat); } } diff --git a/impl/src/main/java/com/stormpath/sdk/impl/application/DefaultApplication.java b/impl/src/main/java/com/stormpath/sdk/impl/application/DefaultApplication.java index 6286f87758..4567c56752 100644 --- a/impl/src/main/java/com/stormpath/sdk/impl/application/DefaultApplication.java +++ b/impl/src/main/java/com/stormpath/sdk/impl/application/DefaultApplication.java @@ -473,6 +473,10 @@ public Account createAccount(CreateAccountRequest request) { href += querySeparator + "passwordFormat=" + request.getPasswordFormat(); } + if (request.isOrganizationNameKeySpecified()) { + href += querySeparator + "organizationNameKey=" + request.getOrganizationNameKey(); + } + if (request.isAccountOptionsSpecified()) { return getDataStore().create(href, account, request.getAccountOptions()); } From 021207679e70cb1df45d2aa0c4d4a7eba4a3e25a Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 3 Feb 2017 10:52:56 -0800 Subject: [PATCH 4/8] issue-1257 adding form properties --- .../stormpath/sdk/servlet/config/web.stormpath.properties | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/extensions/servlet/src/main/resources/com/stormpath/sdk/servlet/config/web.stormpath.properties b/extensions/servlet/src/main/resources/com/stormpath/sdk/servlet/config/web.stormpath.properties index f104b2e4c5..eaf40d8599 100644 --- a/extensions/servlet/src/main/resources/com/stormpath/sdk/servlet/config/web.stormpath.properties +++ b/extensions/servlet/src/main/resources/com/stormpath/sdk/servlet/config/web.stormpath.properties @@ -89,6 +89,12 @@ stormpath.web.register.form.fields.confirmPassword.label = stormpath.web.registe stormpath.web.register.form.fields.confirmPassword.placeholder = stormpath.web.register.form.fields.confirmPassword.placeholder stormpath.web.register.form.fields.confirmPassword.required = true stormpath.web.register.form.fields.confirmPassword.type = password +stormpath.web.register.form.fields.organizationNameKey.enabled = true +stormpath.web.register.form.fields.organizationNameKey.visible = false +stormpath.web.register.form.fields.organizationNameKey.label = Organization Name Key +stormpath.web.register.form.fields.organizationNameKey.placeholder = Organization Name Key +stormpath.web.register.form.fields.organizationNameKey.required = false +stormpath.web.register.form.fields.organizationNameKey.type = text stormpath.web.register.form.fieldOrder = username,givenName,middleName,surname,email,password,confirmPassword stormpath.web.register.view = register # If verify is enabled, the login view will show a link to to a page where users will be able to have the account From 7673ffea423e2a282d04f82b932bdbc1e8953974 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 3 Feb 2017 16:24:42 -0800 Subject: [PATCH 5/8] issue-1257 adding organizationNameKey to /verify POST --- .../sdk/account/VerificationEmailRequest.java | 7 +++++++ .../sdk/account/VerificationEmailRequestBuilder.java | 8 ++++++++ .../stormpath/sdk/servlet/mvc/VerifyController.java | 1 + .../sdk/servlet/config/web.stormpath.properties | 6 ++++++ .../impl/account/DefaultVerificationEmailRequest.java | 11 +++++++++++ .../DefaultVerificationEmailRequestBuilder.java | 8 ++++++++ 6 files changed, 41 insertions(+) diff --git a/api/src/main/java/com/stormpath/sdk/account/VerificationEmailRequest.java b/api/src/main/java/com/stormpath/sdk/account/VerificationEmailRequest.java index b7fc37477d..c5ee30f7a4 100644 --- a/api/src/main/java/com/stormpath/sdk/account/VerificationEmailRequest.java +++ b/api/src/main/java/com/stormpath/sdk/account/VerificationEmailRequest.java @@ -41,6 +41,13 @@ public interface VerificationEmailRequest { */ String getLogin(); + /** + * Returns the organizationNameKey. + * + * @return the organizationNameKey. + */ + String getOrganizationNameKey(); + /** * Returns the {@link AccountStore} set. * diff --git a/api/src/main/java/com/stormpath/sdk/account/VerificationEmailRequestBuilder.java b/api/src/main/java/com/stormpath/sdk/account/VerificationEmailRequestBuilder.java index 71ddbf5cae..f65aede3da 100644 --- a/api/src/main/java/com/stormpath/sdk/account/VerificationEmailRequestBuilder.java +++ b/api/src/main/java/com/stormpath/sdk/account/VerificationEmailRequestBuilder.java @@ -33,6 +33,14 @@ public interface VerificationEmailRequestBuilder { */ VerificationEmailRequestBuilder setLogin(String usernameOrEmail); + /** + * Setter for the account's organizationNameKey information. + * + * @param organizationNameKey the organizationNameKey where the account lives. + * @return this builder instance for method chaining. + */ + VerificationEmailRequestBuilder setOrganizationNameKey(String organizationNameKey); + /** * Setter for the {@link com.stormpath.sdk.directory.AccountStore} where the specified account must be searched. Although * this is an optional property it should to be provided when the account's AccountStore is already known since it will diff --git a/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/mvc/VerifyController.java b/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/mvc/VerifyController.java index 6cb3a43c01..d5f117aa14 100644 --- a/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/mvc/VerifyController.java +++ b/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/mvc/VerifyController.java @@ -230,6 +230,7 @@ protected ViewModel onValidSubmit(HttpServletRequest request, HttpServletRespons VerificationEmailRequest verificationEmailRequest = Applications.verificationEmailBuilder() .setLogin(login) + .setOrganizationNameKey(getFieldValueResolver().getValue(request, "organizationNameKey")) .setAccountStore(accountStore) .build(); diff --git a/extensions/servlet/src/main/resources/com/stormpath/sdk/servlet/config/web.stormpath.properties b/extensions/servlet/src/main/resources/com/stormpath/sdk/servlet/config/web.stormpath.properties index eaf40d8599..8b40c5af79 100644 --- a/extensions/servlet/src/main/resources/com/stormpath/sdk/servlet/config/web.stormpath.properties +++ b/extensions/servlet/src/main/resources/com/stormpath/sdk/servlet/config/web.stormpath.properties @@ -115,6 +115,12 @@ stormpath.web.verifyEmail.form.fields.email.label = stormpath.web.verifyEmail.fo stormpath.web.verifyEmail.form.fields.email.placeholder = stormpath.web.verifyEmail.form.fields.email.placeholder stormpath.web.verifyEmail.form.fields.email.required = true stormpath.web.verifyEmail.form.fields.email.type = text +stormpath.web.verifyEmail.form.fields.organizationNameKey.enabled = true +stormpath.web.verifyEmail.form.fields.organizationNameKey.visible = false +stormpath.web.verifyEmail.form.fields.organizationNameKey.label = Organization Name Key +stormpath.web.verifyEmail.form.fields.organizationNameKey.placeholder = Organization Name Key +stormpath.web.verifyEmail.form.fields.organizationNameKey.required = false +stormpath.web.verifyEmail.form.fields.organizationNameKey.type = text ## default SAML SP initiated endpoint stormpath.web.saml.uri = /saml diff --git a/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultVerificationEmailRequest.java b/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultVerificationEmailRequest.java index f07e90f749..59d4f0b7aa 100644 --- a/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultVerificationEmailRequest.java +++ b/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultVerificationEmailRequest.java @@ -33,6 +33,7 @@ public class DefaultVerificationEmailRequest extends AbstractResource implements // SIMPLE PROPERTIES static final StringProperty LOGIN = new StringProperty("login"); + static final StringProperty ORGANIZATION_NAME_KEY = new StringProperty("organizationNameKey"); // INSTANCE RESOURCE REFERENCES: static final ResourceReference ACCOUNT_STORE = new ResourceReference("accountStore", AccountStore.class); @@ -62,6 +63,16 @@ public VerificationEmailRequest setLogin(String usernameOrEmail) { return this; } + @Override + public String getOrganizationNameKey() { + return getString(ORGANIZATION_NAME_KEY); + } + + public VerificationEmailRequest setOrganizationNameKey(String organizationNameKey) { + setProperty(ORGANIZATION_NAME_KEY, organizationNameKey); + return this; + } + @Override public AccountStore getAccountStore() { return getResourceProperty(ACCOUNT_STORE); diff --git a/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultVerificationEmailRequestBuilder.java b/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultVerificationEmailRequestBuilder.java index b0ee5ad394..6779ea4a50 100644 --- a/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultVerificationEmailRequestBuilder.java +++ b/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultVerificationEmailRequestBuilder.java @@ -27,6 +27,7 @@ public class DefaultVerificationEmailRequestBuilder implements VerificationEmailRequestBuilder { private String login; + private String organizationNameKey; private AccountStore accountStore; @Override @@ -36,6 +37,12 @@ public VerificationEmailRequestBuilder setLogin(String usernameOrEmail) { return this; } + @Override + public VerificationEmailRequestBuilder setOrganizationNameKey(String organizationNameKey) { + this.organizationNameKey = organizationNameKey; + return this; + } + @Override public VerificationEmailRequestBuilder setAccountStore(AccountStore accountStore) { if (accountStore != null && accountStore.getHref() == null) { @@ -51,6 +58,7 @@ public VerificationEmailRequest build() { DefaultVerificationEmailRequest verificationEmailRequest = new DefaultVerificationEmailRequest(null); verificationEmailRequest.setLogin(login); + verificationEmailRequest.setOrganizationNameKey(organizationNameKey); if (accountStore != null) { verificationEmailRequest.setAccountStore(accountStore); } From e0b94403b21eabdb5d7b662cf02dfcf73436a347 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 6 Feb 2017 10:40:22 -0800 Subject: [PATCH 6/8] issue-1257 fixing unit tests --- .../DefaultCreateAccountRequestTest.groovy | 25 ++++++++++++++----- .../application/DefaultApplicationTest.groovy | 2 ++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/impl/src/test/groovy/com/stormpath/sdk/impl/account/DefaultCreateAccountRequestTest.groovy b/impl/src/test/groovy/com/stormpath/sdk/impl/account/DefaultCreateAccountRequestTest.groovy index 77a7ad19d8..c8847a1131 100644 --- a/impl/src/test/groovy/com/stormpath/sdk/impl/account/DefaultCreateAccountRequestTest.groovy +++ b/impl/src/test/groovy/com/stormpath/sdk/impl/account/DefaultCreateAccountRequestTest.groovy @@ -32,7 +32,7 @@ class DefaultCreateAccountRequestTest { @Test void testDefault() { def account = createStrictMock(Account) - def request = new DefaultCreateAccountRequest(account, null, null) + def request = new DefaultCreateAccountRequest(account, null, null, null) assertSame(request.account, account) assertFalse request.isRegistrationWorkflowOptionSpecified() @@ -42,7 +42,7 @@ class DefaultCreateAccountRequestTest { @Test void testWorkflowEnabled() { def account = createStrictMock(Account) - def request = new DefaultCreateAccountRequest(account, true, null) + def request = new DefaultCreateAccountRequest(account, true, null, null) assertSame(request.account, account) assertTrue request.isRegistrationWorkflowOptionSpecified() @@ -52,7 +52,7 @@ class DefaultCreateAccountRequestTest { @Test void testWorkflowDisabled() { def account = createStrictMock(Account) - def request = new DefaultCreateAccountRequest(account, false, null) + def request = new DefaultCreateAccountRequest(account, false, null, null) assertSame(request.account, account) assertTrue request.isRegistrationWorkflowOptionSpecified() @@ -63,7 +63,7 @@ class DefaultCreateAccountRequestTest { void testWorkflowNotSpecifiedButAccessed() { def account = createStrictMock(Account) - def request = new DefaultCreateAccountRequest(account, null, null) + def request = new DefaultCreateAccountRequest(account, null, null, null) request.isRegistrationWorkflowEnabled() } @@ -71,7 +71,7 @@ class DefaultCreateAccountRequestTest { void testAccountCriteria() { def account = createStrictMock(Account) def criteria = createStrictMock(AccountCriteria) - def request = new DefaultCreateAccountRequest(account, null, criteria) + def request = new DefaultCreateAccountRequest(account, null, criteria, null) assertSame(request.account, account) assertFalse request.isRegistrationWorkflowOptionSpecified() @@ -79,10 +79,23 @@ class DefaultCreateAccountRequestTest { assertSame(request.accountOptions, criteria) } + @Test + void testAccountOrganizationNameKey() { + def account = createStrictMock(Account) + def criteria = createStrictMock(AccountCriteria) + def request = new DefaultCreateAccountRequest(account, null, criteria, "onk") + + assertSame(request.account, account) + assertFalse request.isRegistrationWorkflowOptionSpecified() + assertTrue request.isAccountOptionsSpecified() + assertSame(request.accountOptions, criteria) + assertSame(request.organizationNameKey, "onk") + } + @Test(expectedExceptions = IllegalStateException) void testAccountCriteriaNotSpecifiedButAccessed() { def account = createStrictMock(Account) - def request = new DefaultCreateAccountRequest(account, null, null) + def request = new DefaultCreateAccountRequest(account, null, null, null) request.getAccountOptions() } diff --git a/impl/src/test/groovy/com/stormpath/sdk/impl/application/DefaultApplicationTest.groovy b/impl/src/test/groovy/com/stormpath/sdk/impl/application/DefaultApplicationTest.groovy index 570814d577..bf9540b0ea 100644 --- a/impl/src/test/groovy/com/stormpath/sdk/impl/application/DefaultApplicationTest.groovy +++ b/impl/src/test/groovy/com/stormpath/sdk/impl/application/DefaultApplicationTest.groovy @@ -306,6 +306,7 @@ class DefaultApplicationTest { expect(request.getAccount()).andReturn(account) expect(request.isRegistrationWorkflowOptionSpecified()).andReturn(false) expect(request.isPasswordFormatSpecified()).andReturn(false) + expect(request.isOrganizationNameKeySpecified()).andReturn(false) expect(request.isAccountOptionsSpecified()).andReturn(false) expect(internalDataStore.instantiate(AccountList, [href: "https://api.stormpath.com/v1/applications/jefoifj93riu23ioj/accounts"])).andReturn(accountList) expect(accountList.getHref()).andReturn("https://api.stormpath.com/v1/applications/jefoifj93riu23ioj/accounts") @@ -341,6 +342,7 @@ class DefaultApplicationTest { expect(request.isRegistrationWorkflowOptionSpecified()).andReturn(true) expect(request.isRegistrationWorkflowEnabled()).andReturn(false) expect(request.isPasswordFormatSpecified()).andReturn(false) + expect(request.isOrganizationNameKeySpecified()).andReturn(false) expect(request.isAccountOptionsSpecified()).andReturn(true) expect(request.getAccountOptions()).andReturn(accountCriteria) expect(internalDataStore.instantiate(AccountList, [href: "https://api.stormpath.com/v1/applications/jefoifj93riu23ioj/accounts"])).andReturn(accountList) From ab118ea2c24f31cf41f91fd970a16370f1e24fa3 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 6 Feb 2017 11:33:02 -0800 Subject: [PATCH 7/8] issue-1257 adding organizationNameKey support for reset password --- .../sdk/account/PasswordResetToken.java | 2 ++ .../sdk/application/Application.java | 26 +++++++++++++++++++ .../SpecConfigVersusWebPropertiesTest.groovy | 2 +- .../account/DefaultPasswordResetToken.java | 13 +++++++++- .../impl/application/DefaultApplication.java | 15 ++++++++--- 5 files changed, 53 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/com/stormpath/sdk/account/PasswordResetToken.java b/api/src/main/java/com/stormpath/sdk/account/PasswordResetToken.java index 8a2dfaf5ac..8e13363a50 100644 --- a/api/src/main/java/com/stormpath/sdk/account/PasswordResetToken.java +++ b/api/src/main/java/com/stormpath/sdk/account/PasswordResetToken.java @@ -24,6 +24,8 @@ public interface PasswordResetToken extends Resource { String getEmail(); + String getOrganizationNameKey(); + Account getAccount(); /** diff --git a/api/src/main/java/com/stormpath/sdk/application/Application.java b/api/src/main/java/com/stormpath/sdk/application/Application.java index 1a3d989e75..1f3e6cc5e2 100644 --- a/api/src/main/java/com/stormpath/sdk/application/Application.java +++ b/api/src/main/java/com/stormpath/sdk/application/Application.java @@ -408,6 +408,32 @@ public interface Application extends AccountStoreHolder, Resource, */ PasswordResetToken sendPasswordResetEmail(String email, AccountStore accountStore) throws ResourceException; + /** + * Sends a password reset email to an account in the specified {@code Organization} matching the specified + * {@code email} address. If the email does not match an account in the specified Organization, a + * ResourceException will be thrown. If you are unsure of which of the application's mapped account stores might + * contain the account, use the more general + * {@link #sendPasswordResetEmail(String) sendPasswordResetEmail(String email)} method instead. + * + *

This method is useful if you want to target a specific organization context for multi-tenancy purposes.

+ * + *

Like the {@link #sendPasswordResetEmail(String)} method, this email merely sends the email that contains + * a link that, when clicked, will take the user to a view (web page) that allows them to specify a new password. + * When the new password is submitted, the {@link #verifyPasswordResetToken(String)} method is expected to be + * called at that time.

+ * + * @param email an email address of an Account that may login to the application. + * @param organizationNameKey the organizationNameKey expected to contain an account with the specified email address + * @return the {@code PasswordResetToken} created for the password reset email sent to the specified {@code email} + * @see #sendPasswordResetEmail(String) + * @see #verifyPasswordResetToken(String) + * @see #resetPassword(String, String) + * @throws ResourceException if the specified AccountStore is not mapped to this application or if the email address + * is not in the specified Account store + * @since 1.6.0 + */ + PasswordResetToken sendPasswordResetEmail(String email, String organizationNameKey) throws ResourceException; + /** * Verifies a password reset token in a user-clicked link within an email. *

diff --git a/extensions/servlet/src/test/groovy/com/stormpath/sdk/servlet/config/SpecConfigVersusWebPropertiesTest.groovy b/extensions/servlet/src/test/groovy/com/stormpath/sdk/servlet/config/SpecConfigVersusWebPropertiesTest.groovy index 39dea912d7..355dc53158 100644 --- a/extensions/servlet/src/test/groovy/com/stormpath/sdk/servlet/config/SpecConfigVersusWebPropertiesTest.groovy +++ b/extensions/servlet/src/test/groovy/com/stormpath/sdk/servlet/config/SpecConfigVersusWebPropertiesTest.groovy @@ -85,7 +85,7 @@ class SpecConfigVersusWebPropertiesTest { specProperties.containsKey(k) ? null : k } - def expected_diff_size = 87 + def expected_diff_size = 93 if (diff.size != expected_diff_size) { println "It looks like a property was added or removed from the Framework Spec or web.stormpath.properties." diff --git a/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultPasswordResetToken.java b/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultPasswordResetToken.java index 3da7f77591..96f7620cbc 100644 --- a/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultPasswordResetToken.java +++ b/impl/src/main/java/com/stormpath/sdk/impl/account/DefaultPasswordResetToken.java @@ -35,13 +35,14 @@ public class DefaultPasswordResetToken extends AbstractResource implements Passw // SIMPLE PROPERTIES static final StringProperty EMAIL = new StringProperty("email"); + static final StringProperty ORGANIZATION_NAME_KEY = new StringProperty("organizationNameKey"); static final StringProperty PASSWORD = new StringProperty("password"); // INSTANCE RESOURCE REFERENCES: static final ResourceReference ACCOUNT = new ResourceReference("account", Account.class); static final ResourceReference ACCOUNT_STORE = new ResourceReference("accountStore", AccountStore.class); - private static final Map PROPERTY_DESCRIPTORS = createPropertyDescriptorMap(EMAIL, ACCOUNT_STORE, PASSWORD, ACCOUNT); + private static final Map PROPERTY_DESCRIPTORS = createPropertyDescriptorMap(EMAIL, ACCOUNT_STORE, PASSWORD, ACCOUNT, ORGANIZATION_NAME_KEY); public DefaultPasswordResetToken(InternalDataStore dataStore) { super(dataStore); @@ -66,6 +67,16 @@ public PasswordResetToken setEmail(String email) { return this; } + @Override + public String getOrganizationNameKey() { + return getString(ORGANIZATION_NAME_KEY); + } + + public PasswordResetToken setOrganizationNameKey(String organizationNameKey) { + setProperty(ORGANIZATION_NAME_KEY, organizationNameKey); + return this; + } + @Override public Account getAccount() { return getResourceProperty(ACCOUNT); diff --git a/impl/src/main/java/com/stormpath/sdk/impl/application/DefaultApplication.java b/impl/src/main/java/com/stormpath/sdk/impl/application/DefaultApplication.java index 4567c56752..3fa141ce94 100644 --- a/impl/src/main/java/com/stormpath/sdk/impl/application/DefaultApplication.java +++ b/impl/src/main/java/com/stormpath/sdk/impl/application/DefaultApplication.java @@ -306,22 +306,31 @@ public Tenant getTenant() { @Override public PasswordResetToken sendPasswordResetEmail(String email) { - PasswordResetToken token = createPasswordResetToken(email, null); + PasswordResetToken token = createPasswordResetToken(email, null, null); return token; } @Override public PasswordResetToken sendPasswordResetEmail(String email, AccountStore accountStore) throws ResourceException { - PasswordResetToken token = createPasswordResetToken(email, accountStore); + PasswordResetToken token = createPasswordResetToken(email, accountStore, null); return token; } - private PasswordResetToken createPasswordResetToken(String email, AccountStore accountStore) { + @Override + public PasswordResetToken sendPasswordResetEmail(String email, String organizationNameKey) throws ResourceException { + PasswordResetToken token = createPasswordResetToken(email, null, organizationNameKey); + return token; + } + + private PasswordResetToken createPasswordResetToken(String email, AccountStore accountStore, String organizationNameKey) { DefaultPasswordResetToken passwordResetToken = (DefaultPasswordResetToken) getDataStore().instantiate(PasswordResetToken.class); passwordResetToken.setEmail(email); if (accountStore != null) { passwordResetToken.setAccountStore(accountStore); } + if (organizationNameKey != null) { + passwordResetToken.setOrganizationNameKey(organizationNameKey); + } String href = getPasswordResetTokensHref(); return getDataStore().create(href, passwordResetToken); } From 097bde0e444738199125f6f5c9c7b48f110d64c1 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 6 Feb 2017 12:00:02 -0800 Subject: [PATCH 8/8] issue-1257 fixing unit test --- .../sdk/impl/account/DefaultPasswordResetTokenTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impl/src/test/groovy/com/stormpath/sdk/impl/account/DefaultPasswordResetTokenTest.groovy b/impl/src/test/groovy/com/stormpath/sdk/impl/account/DefaultPasswordResetTokenTest.groovy index c13c41ecc3..d76465cb28 100644 --- a/impl/src/test/groovy/com/stormpath/sdk/impl/account/DefaultPasswordResetTokenTest.groovy +++ b/impl/src/test/groovy/com/stormpath/sdk/impl/account/DefaultPasswordResetTokenTest.groovy @@ -43,7 +43,7 @@ class DefaultPasswordResetTokenTest { assertTrue(resourceWithDS instanceof DefaultPasswordResetToken && resourceWithProps instanceof DefaultPasswordResetToken) def pd = resourceWithProps.getPropertyDescriptors() - assertEquals(pd.size(), 4) + assertEquals(pd.size(), 5) assertTrue(pd.email instanceof StringProperty) assertTrue(pd.account instanceof ResourceReference) assertEquals(pd.account.type, Account)