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/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/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/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/api/src/main/java/com/stormpath/sdk/oauth/OAuthPasswordGrantRequestAuthentication.java b/api/src/main/java/com/stormpath/sdk/oauth/OAuthPasswordGrantRequestAuthentication.java index 67708354bf..1e21d74cb3 100644 --- a/api/src/main/java/com/stormpath/sdk/oauth/OAuthPasswordGrantRequestAuthentication.java +++ b/api/src/main/java/com/stormpath/sdk/oauth/OAuthPasswordGrantRequestAuthentication.java @@ -45,4 +45,11 @@ public interface OAuthPasswordGrantRequestAuthentication extends OAuthGrantReque */ AccountStore getAccountStore(); + /** + * Returns the specific organizationNameKey where the provided credentials will be sought in order to authenticate a request. + * + * @return the specific organizationNameKey where the provided credentials will be sought in order to authenticate a request. + */ + String getOrganizationNameKey(); + } diff --git a/api/src/main/java/com/stormpath/sdk/oauth/OAuthPasswordGrantRequestAuthenticationBuilder.java b/api/src/main/java/com/stormpath/sdk/oauth/OAuthPasswordGrantRequestAuthenticationBuilder.java index 4d30bb7aa4..0ad2e361eb 100644 --- a/api/src/main/java/com/stormpath/sdk/oauth/OAuthPasswordGrantRequestAuthenticationBuilder.java +++ b/api/src/main/java/com/stormpath/sdk/oauth/OAuthPasswordGrantRequestAuthenticationBuilder.java @@ -47,4 +47,12 @@ public interface OAuthPasswordGrantRequestAuthenticationBuilder extends OAuthReq * @return this instance for method chaining. */ OAuthPasswordGrantRequestAuthenticationBuilder setAccountStore(AccountStore accountStore); + + /** + * Specifies the target Organization via nameKey to be used for the authentication token creation. + * + * @param organizationNameKey the sole specific nameKey of the {@link com.stormpath.sdk.organization.Organization organization} where the provided credentials will be sought in order to authenticate this request. + * @return this instance for method chaining. + */ + OAuthPasswordGrantRequestAuthenticationBuilder setOrganizationNameKey(String organizationNameKey); } diff --git a/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/filter/oauth/DefaultAccessTokenAuthenticationRequestFactory.java b/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/filter/oauth/DefaultAccessTokenAuthenticationRequestFactory.java index 42db909283..6f3586ca26 100644 --- a/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/filter/oauth/DefaultAccessTokenAuthenticationRequestFactory.java +++ b/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/filter/oauth/DefaultAccessTokenAuthenticationRequestFactory.java @@ -61,6 +61,10 @@ public OAuthPasswordGrantRequestAuthentication createAccessTokenAuthenticationRe requestBuilder.setAccountStore(accountStore); } + if (request.getParameter("organizationNameKey") != null) { + requestBuilder.setOrganizationNameKey(request.getParameter("organizationNameKey")); + } + return requestBuilder.build(); } catch (Exception e){ throw new OAuthException(OAuthErrorCode.INVALID_REQUEST); 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/java/com/stormpath/sdk/servlet/mvc/provider/ExternalAccountStoreModelFactory.java b/extensions/servlet/src/main/java/com/stormpath/sdk/servlet/mvc/provider/ExternalAccountStoreModelFactory.java index 625d1343c0..7af07a0c77 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,20 +15,26 @@ */ 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; import com.stormpath.sdk.application.webconfig.ApplicationWebConfig; import com.stormpath.sdk.application.webconfig.ApplicationWebConfigStatus; import com.stormpath.sdk.directory.AccountStore; +import com.stormpath.sdk.directory.AccountStoreVisitor; import com.stormpath.sdk.directory.AccountStoreVisitorAdapter; 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; @@ -49,17 +55,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(); @@ -69,6 +83,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; 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..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 @@ -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 @@ -109,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/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/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/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/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); } 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..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); } @@ -473,6 +482,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()); } diff --git a/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantAuthenticationAttempt.java b/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantAuthenticationAttempt.java index a553884f70..be7f47a562 100644 --- a/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantAuthenticationAttempt.java +++ b/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantAuthenticationAttempt.java @@ -31,9 +31,10 @@ public class DefaultOAuthPasswordGrantAuthenticationAttempt extends AbstractReso static final StringProperty LOGIN = new StringProperty("username"); static final StringProperty PASSWORD = new StringProperty("password"); static final StringProperty ACCOUNT_STORE_HREF = new StringProperty("accountStore"); + static final StringProperty ORGANIZATION_NAME_KEY = new StringProperty("organizationNameKey"); static final StringProperty GRANT_TYPE = new StringProperty("grant_type"); - private static final Map PROPERTY_DESCRIPTORS = createPropertyDescriptorMap(LOGIN, PASSWORD, ACCOUNT_STORE_HREF, GRANT_TYPE); + private static final Map PROPERTY_DESCRIPTORS = createPropertyDescriptorMap(LOGIN, PASSWORD, ACCOUNT_STORE_HREF, ORGANIZATION_NAME_KEY, GRANT_TYPE); public DefaultOAuthPasswordGrantAuthenticationAttempt(InternalDataStore dataStore) { super(dataStore); @@ -58,6 +59,11 @@ public void setAccountStore(AccountStore value) { setProperty(ACCOUNT_STORE_HREF, value.getHref()); } + @Override + public void setOrganizationNameKey(String organizationNameKey) { + setProperty(ORGANIZATION_NAME_KEY, organizationNameKey); + } + public String getLogin() { return getString(LOGIN); } diff --git a/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantRequestAuthentication.java b/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantRequestAuthentication.java index 6cc6485a9a..8be80ddfa5 100644 --- a/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantRequestAuthentication.java +++ b/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantRequestAuthentication.java @@ -27,6 +27,7 @@ public class DefaultOAuthPasswordGrantRequestAuthentication implements OAuthPass private final String login; private final String password; private AccountStore accountStore; + private String organizationNameKey; private final static String grant_type = "password"; public DefaultOAuthPasswordGrantRequestAuthentication(String login, String password) { @@ -42,6 +43,11 @@ public OAuthPasswordGrantRequestAuthentication setAccountStore(AccountStore acco return this; } + public OAuthPasswordGrantRequestAuthentication setOrganizationNameKey(String organizationNameKey) { + this.organizationNameKey = organizationNameKey; + return this; + } + @Override public String getPassword() { return password; @@ -57,6 +63,10 @@ public AccountStore getAccountStore() { return accountStore; } + public String getOrganizationNameKey() { + return organizationNameKey; + } + @Override public String getGrantType() { return grant_type; diff --git a/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantRequestAuthenticationBuilder.java b/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantRequestAuthenticationBuilder.java index d0d9804ee5..ba64c50884 100644 --- a/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantRequestAuthenticationBuilder.java +++ b/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantRequestAuthenticationBuilder.java @@ -28,6 +28,7 @@ public class DefaultOAuthPasswordGrantRequestAuthenticationBuilder implements OA private String login; private String password; private AccountStore accountStore; + private String organizationNameKey; @Override public OAuthPasswordGrantRequestAuthenticationBuilder setLogin(String login) { @@ -50,6 +51,13 @@ public OAuthPasswordGrantRequestAuthenticationBuilder setAccountStore(AccountSto return this; } + @Override + public OAuthPasswordGrantRequestAuthenticationBuilder setOrganizationNameKey(String organizationNameKey) { + Assert.hasText(organizationNameKey, "organizationNameKey cannot be null or empty."); + this.organizationNameKey = organizationNameKey; + return this; + } + @Override public OAuthPasswordGrantRequestAuthentication build() { Assert.state(this.login != null, "login has not been set. It is a required attribute."); @@ -57,10 +65,17 @@ public OAuthPasswordGrantRequestAuthentication build() { DefaultOAuthPasswordGrantRequestAuthentication request = new DefaultOAuthPasswordGrantRequestAuthentication(login, password); + Assert.isTrue((this.accountStore == null && this.organizationNameKey == null) || + this.accountStore != null ^ this.organizationNameKey != null, "only set accountStore or organizationNameKey or neither"); + if (this.accountStore != null) { request.setAccountStore(this.accountStore); } + if (this.organizationNameKey != null) { + request.setOrganizationNameKey(this.organizationNameKey); + } + return request; } } diff --git a/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantRequestAuthenticator.java b/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantRequestAuthenticator.java index 2a2779989d..5ef3e0d52d 100644 --- a/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantRequestAuthenticator.java +++ b/impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultOAuthPasswordGrantRequestAuthenticator.java @@ -46,6 +46,9 @@ public OAuthGrantRequestAuthenticationResult authenticate(OAuthRequestAuthentica if (oauthPasswordGrantRequestAuthentication.getAccountStore() != null){ oauthPasswordGrantAuthenticationAttempt.setAccountStore(oauthPasswordGrantRequestAuthentication.getAccountStore()); } + if (oauthPasswordGrantRequestAuthentication.getOrganizationNameKey() != null) { + oauthPasswordGrantAuthenticationAttempt.setOrganizationNameKey(oauthPasswordGrantRequestAuthentication.getOrganizationNameKey()); + } HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED); diff --git a/impl/src/main/java/com/stormpath/sdk/impl/oauth/OAuthPasswordGrantAuthenticationAttempt.java b/impl/src/main/java/com/stormpath/sdk/impl/oauth/OAuthPasswordGrantAuthenticationAttempt.java index d03ada3421..d3c9817076 100644 --- a/impl/src/main/java/com/stormpath/sdk/impl/oauth/OAuthPasswordGrantAuthenticationAttempt.java +++ b/impl/src/main/java/com/stormpath/sdk/impl/oauth/OAuthPasswordGrantAuthenticationAttempt.java @@ -43,6 +43,12 @@ public interface OAuthPasswordGrantAuthenticationAttempt extends Resource { */ void setAccountStore(AccountStore accountStore); + /** + * Method used to set the organizationNameKey object that will be used for the token exchange request. + * @param organizationNameKey the organizationNameKey that will be used for the token exchange request. + */ + void setOrganizationNameKey(String organizationNameKey); + /** * Method used to set the Authentication Grant Type that will be used for the token exchange request. Currently only "password" grant type is supported for this operation. * @param grantType the Authentication Grant Type that will be used for the token exchange request. 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/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) 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) 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) }