com.stormpath.sdk.impl.application.DefaultApplication Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of stormpath-sdk-impl Show documentation
Show all versions of stormpath-sdk-impl Show documentation
The Stormpath Java SDK core implemenation .jar is used at runtime to support API invocations. This
implementation jar should be a runtime dependency only and should NOT be depended on at compile time by
your code. The implementations within this jar can change at any time without warning - use it with runtime
scope only.
/*
* Copyright 2016 Stormpath, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.stormpath.sdk.impl.application;
import com.stormpath.sdk.account.Account;
import com.stormpath.sdk.account.AccountCriteria;
import com.stormpath.sdk.account.AccountLinkingPolicy;
import com.stormpath.sdk.account.AccountList;
import com.stormpath.sdk.account.Accounts;
import com.stormpath.sdk.account.CreateAccountRequest;
import com.stormpath.sdk.account.PasswordResetToken;
import com.stormpath.sdk.account.VerificationEmailRequest;
import com.stormpath.sdk.api.ApiKey;
import com.stormpath.sdk.api.ApiKeyCriteria;
import com.stormpath.sdk.api.ApiKeyList;
import com.stormpath.sdk.api.ApiKeyOptions;
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.ApplicationOptions;
import com.stormpath.sdk.application.ApplicationStatus;
import com.stormpath.sdk.application.OAuthApplication;
import com.stormpath.sdk.application.webconfig.ApplicationWebConfig;
import com.stormpath.sdk.authc.AuthenticationRequest;
import com.stormpath.sdk.authc.AuthenticationResult;
import com.stormpath.sdk.directory.AccountStore;
import com.stormpath.sdk.directory.Directories;
import com.stormpath.sdk.directory.Directory;
import com.stormpath.sdk.directory.DirectoryCriteria;
import com.stormpath.sdk.directory.DirectoryList;
import com.stormpath.sdk.group.CreateGroupRequest;
import com.stormpath.sdk.group.Group;
import com.stormpath.sdk.group.GroupCriteria;
import com.stormpath.sdk.group.GroupList;
import com.stormpath.sdk.group.Groups;
import com.stormpath.sdk.http.HttpRequest;
import com.stormpath.sdk.idsite.IdSiteCallbackHandler;
import com.stormpath.sdk.idsite.IdSiteUrlBuilder;
import com.stormpath.sdk.impl.account.DefaultPasswordResetToken;
import com.stormpath.sdk.impl.account.DefaultVerificationEmailRequest;
import com.stormpath.sdk.impl.api.DefaultApiKeyCriteria;
import com.stormpath.sdk.impl.api.DefaultApiKeyOptions;
import com.stormpath.sdk.impl.authc.AuthenticationRequestDispatcher;
import com.stormpath.sdk.impl.ds.InternalDataStore;
import com.stormpath.sdk.impl.idsite.DefaultIdSiteCallbackHandler;
import com.stormpath.sdk.impl.idsite.DefaultIdSiteUrlBuilder;
import com.stormpath.sdk.impl.oauth.DefaultIdSiteAuthenticator;
import com.stormpath.sdk.impl.oauth.DefaultOAuthBearerRequestAuthenticator;
import com.stormpath.sdk.impl.oauth.DefaultOAuthClientCredentialsGrantRequestAuthenticator;
import com.stormpath.sdk.impl.oauth.DefaultOAuthPasswordGrantRequestAuthenticator;
import com.stormpath.sdk.impl.oauth.DefaultOAuthRefreshTokenRequestAuthenticator;
import com.stormpath.sdk.impl.oauth.DefaultOAuthStormpathFactorChallengeGrantRequestAuthenticator;
import com.stormpath.sdk.impl.oauth.DefaultOAuthStormpathSocialGrantRequestAuthenticator;
import com.stormpath.sdk.impl.oauth.DefaultOAuthTokenRevocator;
import com.stormpath.sdk.impl.provider.ProviderAccountResolver;
import com.stormpath.sdk.impl.query.DefaultEqualsExpressionFactory;
import com.stormpath.sdk.impl.query.Expandable;
import com.stormpath.sdk.impl.query.Expansion;
import com.stormpath.sdk.impl.resource.AbstractExtendableInstanceResource;
import com.stormpath.sdk.impl.resource.CollectionReference;
import com.stormpath.sdk.impl.resource.EnumProperty;
import com.stormpath.sdk.impl.resource.ListProperty;
import com.stormpath.sdk.impl.resource.Property;
import com.stormpath.sdk.impl.resource.ResourceReference;
import com.stormpath.sdk.impl.resource.StringProperty;
import com.stormpath.sdk.impl.saml.DefaultSamlCallbackHandler;
import com.stormpath.sdk.impl.saml.DefaultSamlIdpUrlBuilder;
import com.stormpath.sdk.lang.Assert;
import com.stormpath.sdk.lang.Classes;
import com.stormpath.sdk.oauth.IdSiteAuthenticator;
import com.stormpath.sdk.oauth.OAuthApiRequestAuthenticator;
import com.stormpath.sdk.oauth.OAuthBearerRequestAuthenticator;
import com.stormpath.sdk.oauth.OAuthClientCredentialsGrantRequestAuthenticator;
import com.stormpath.sdk.oauth.OAuthPasswordGrantRequestAuthenticator;
import com.stormpath.sdk.oauth.OAuthPolicy;
import com.stormpath.sdk.oauth.OAuthRefreshTokenRequestAuthenticator;
import com.stormpath.sdk.oauth.OAuthStormpathFactorChallengeGrantRequestAuthenticator;
import com.stormpath.sdk.oauth.OAuthStormpathSocialGrantRequestAuthenticator;
import com.stormpath.sdk.oauth.OAuthTokenRevocator;
import com.stormpath.sdk.organization.Organization;
import com.stormpath.sdk.organization.OrganizationCriteria;
import com.stormpath.sdk.organization.OrganizationList;
import com.stormpath.sdk.provider.ProviderAccountRequest;
import com.stormpath.sdk.provider.ProviderAccountResult;
import com.stormpath.sdk.query.Criteria;
import com.stormpath.sdk.resource.ResourceException;
import com.stormpath.sdk.saml.SamlCallbackHandler;
import com.stormpath.sdk.saml.SamlIdpUrlBuilder;
import com.stormpath.sdk.saml.SamlPolicy;
import com.stormpath.sdk.tenant.Tenant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.stormpath.sdk.impl.api.ApiKeyParameter.ID;
/** @since 0.2 */
public class DefaultApplication extends AbstractExtendableInstanceResource implements Application, OAuthApplication {
private static final String OAUTH_REQUEST_AUTHENTICATOR_FQCN =
"com.stormpath.sdk.impl.oauth.authc.DefaultOAuthRequestAuthenticator";
private static final String OAUTH_BUILDER_NOT_AVAILABLE_MSG;
private static final String OAUTH_AUTHENTICATION_REQUEST_DISPATCHER_FQCN =
"com.stormpath.sdk.impl.oauth.authc.OAuthAuthenticationRequestDispatcher";
private static final Class OAUTH_AUTHENTICATION_REQUEST_BUILDER_CLASS;
private static final Class AUTHENTICATION_REQUEST_DISPATCHER_CLASS;
private static final String HTTP_SERVLET_REQUEST_FQCN = "javax.servlet.http.HttpServletRequest";
private static final Set HTTP_REQUEST_SUPPORTED_CLASSES;
private static final String HTTP_REQUEST_NOT_SUPPORTED_MSG =
"Class [%s] is not one of the supported http requests classes [%s].";
private static final String INVALID_URI_FORMAT_MSG = "The provided URI does not match a valid URI scheme.";
static {
if (Classes.isAvailable(OAUTH_REQUEST_AUTHENTICATOR_FQCN)) {
OAUTH_AUTHENTICATION_REQUEST_BUILDER_CLASS = Classes.forName(OAUTH_REQUEST_AUTHENTICATOR_FQCN);
} else {
OAUTH_AUTHENTICATION_REQUEST_BUILDER_CLASS = null;
}
if (Classes.isAvailable(OAUTH_AUTHENTICATION_REQUEST_DISPATCHER_FQCN)) {
AUTHENTICATION_REQUEST_DISPATCHER_CLASS = Classes.forName(OAUTH_AUTHENTICATION_REQUEST_DISPATCHER_FQCN);
} else {
AUTHENTICATION_REQUEST_DISPATCHER_CLASS = AuthenticationRequestDispatcher.class;
}
OAUTH_BUILDER_NOT_AVAILABLE_MSG = "Unable to find the '" + OAUTH_REQUEST_AUTHENTICATOR_FQCN +
"' implementation on the classpath. Please ensure you " +
"have added the stormpath-sdk-oauth-{version}.jar file to your runtime classpath.";
Set supportedClasses = new HashSet();
supportedClasses.add(HttpRequest.class);
if (Classes.isAvailable(HTTP_SERVLET_REQUEST_FQCN)) {
supportedClasses.add(Classes.forName(HTTP_SERVLET_REQUEST_FQCN));
}
HTTP_REQUEST_SUPPORTED_CLASSES = supportedClasses;
}
private static final Logger log = LoggerFactory.getLogger(DefaultApplication.class);
// SIMPLE PROPERTIES:
static final StringProperty NAME = new StringProperty("name");
static final StringProperty DESCRIPTION = new StringProperty("description");
static final EnumProperty STATUS =
new EnumProperty(ApplicationStatus.class);
// INSTANCE RESOURCE REFERENCES:
static final ResourceReference TENANT =
new ResourceReference("tenant", Tenant.class);
static final ResourceReference DEFAULT_ACCOUNT_STORE_MAPPING =
new ResourceReference("defaultAccountStoreMapping", ApplicationAccountStoreMapping.class);
static final ResourceReference DEFAULT_GROUP_STORE_MAPPING =
new ResourceReference("defaultGroupStoreMapping", ApplicationAccountStoreMapping.class);
static final ResourceReference OAUTH_POLICY =
new ResourceReference("oAuthPolicy", OAuthPolicy.class);
static final ResourceReference SAML_POLICY =
new ResourceReference("samlPolicy", SamlPolicy.class);
static final ResourceReference ACCOUNT_LINKING_POLICY =
new ResourceReference("accountLinkingPolicy", AccountLinkingPolicy.class);
static final ResourceReference WEB_CONFIGURATION =
new ResourceReference<>("webConfig", ApplicationWebConfig.class);
// COLLECTION RESOURCE REFERENCES:
static final CollectionReference ACCOUNTS =
new CollectionReference("accounts", AccountList.class, Account.class);
static final CollectionReference GROUPS =
new CollectionReference("groups", GroupList.class, Group.class);
static final CollectionReference ACCOUNT_STORE_MAPPINGS =
new CollectionReference("accountStoreMappings",
ApplicationAccountStoreMappingList.class,
ApplicationAccountStoreMapping.class);
static final CollectionReference PASSWORD_RESET_TOKENS =
new CollectionReference("passwordResetTokens",
PasswordResetTokenList.class,
PasswordResetToken.class);
// LIST PROPERTIES
static final ListProperty AUTHORIZED_CALLBACK_URIS = new ListProperty("authorizedCallbackUris");
public static final String AUTHORIZED_CALLBACK_URIS_PROPERTY_NAME = "authorizedCallbackUris";
public static final String AUTHORIZED_ORIGIN_URIS_PROPERTY_NAME = "authorizedOriginUris";
static final Map PROPERTY_DESCRIPTORS = createPropertyDescriptorMap(
NAME, DESCRIPTION, STATUS, TENANT, DEFAULT_ACCOUNT_STORE_MAPPING, DEFAULT_GROUP_STORE_MAPPING, ACCOUNTS, GROUPS,
ACCOUNT_STORE_MAPPINGS, PASSWORD_RESET_TOKENS, CUSTOM_DATA, OAUTH_POLICY, AUTHORIZED_CALLBACK_URIS, SAML_POLICY,
ACCOUNT_LINKING_POLICY, WEB_CONFIGURATION);
public DefaultApplication(InternalDataStore dataStore) {
super(dataStore);
}
public DefaultApplication(InternalDataStore dataStore, Map properties) {
super(dataStore, properties);
}
@Override
public Map getPropertyDescriptors() {
return PROPERTY_DESCRIPTORS;
}
@Override
public String getName() {
return getString(NAME);
}
@Override
public Application setName(String name) {
setProperty(NAME, name);
return this;
}
@Override
public String getDescription() {
return getString(DESCRIPTION);
}
@Override
public Application setDescription(String description) {
setProperty(DESCRIPTION, description);
return this;
}
@Override
public ApplicationStatus getStatus() {
return getEnumProperty(STATUS);
}
@Override
public Application setStatus(ApplicationStatus status) {
setProperty(STATUS, status);
return this;
}
@Override
public AccountList getAccounts() {
return getResourceProperty(ACCOUNTS);
}
@Override
public AccountList getAccounts(Map queryParams) {
AccountList list = getAccounts(); //safe to get the href: does not execute a query until iteration occurs
return getDataStore().getResource(list.getHref(), AccountList.class, queryParams);
}
@Override
public AccountList getAccounts(AccountCriteria criteria) {
AccountList list = getAccounts(); //safe to get the href: does not execute a query until iteration occurs
return getDataStore().getResource(list.getHref(), AccountList.class, (Criteria) criteria);
}
@Override
//since 0.8
public GroupList getGroups() {
return getResourceProperty(GROUPS);
}
@Override
public GroupList getGroups(Map queryParams) {
GroupList list = getGroups(); //safe to get the href: does not execute a query until iteration occurs
return getDataStore().getResource(list.getHref(), GroupList.class, queryParams);
}
@Override
public GroupList getGroups(GroupCriteria criteria) {
GroupList groups = getGroups(); //safe to get the href: does not execute a query until iteration occurs
return getDataStore().getResource(groups.getHref(), GroupList.class, (Criteria) criteria);
}
@Override
public Tenant getTenant() {
return getResourceProperty(TENANT);
}
@Override
public PasswordResetToken sendPasswordResetEmail(String email) {
PasswordResetToken token = createPasswordResetToken(email, null);
return token;
}
@Override
public PasswordResetToken sendPasswordResetEmail(String email, AccountStore accountStore) throws ResourceException {
PasswordResetToken token = createPasswordResetToken(email, accountStore);
return token;
}
private PasswordResetToken createPasswordResetToken(String email, AccountStore accountStore) {
DefaultPasswordResetToken passwordResetToken = (DefaultPasswordResetToken) getDataStore().instantiate(PasswordResetToken.class);
passwordResetToken.setEmail(email);
if (accountStore != null) {
passwordResetToken.setAccountStore(accountStore);
}
String href = getPasswordResetTokensHref();
return getDataStore().create(href, passwordResetToken);
}
private String getPasswordResetTokensHref() {
Map passwordResetTokensLink =
(Map) getProperty(PASSWORD_RESET_TOKENS.getName());
return passwordResetTokensLink.get(HREF_PROP_NAME);
}
// @since 1.0.RC8
public SamlPolicy getSamlPolicy() {
return getResourceProperty(SAML_POLICY);
}
@Override
public ApplicationWebConfig getWebConfig() {
return getResourceProperty(WEB_CONFIGURATION);
}
// @since 1.0.RC8
public List getAuthorizedCallbackUris() {
return new ArrayList(getListProperty(AUTHORIZED_CALLBACK_URIS_PROPERTY_NAME));
}
// @since 1.0.RC8
@Override
public Application setAuthorizedCallbackUris(List authorizedCallbackUris) {
setProperty(AUTHORIZED_CALLBACK_URIS_PROPERTY_NAME, authorizedCallbackUris);
save();
return this;
}
// @since 1.0.RC8
@Override
public Application addAuthorizedCallbackUri(String authorizedCallbackUri) {
// validate URI
this.validateUri(authorizedCallbackUri);
List authorizedCallbackUris = this.getAuthorizedCallbackUris();
authorizedCallbackUris.add(authorizedCallbackUri);
setProperty(AUTHORIZED_CALLBACK_URIS_PROPERTY_NAME, authorizedCallbackUris);
save();
return this;
}
@Override
public List getAuthorizedOriginUris() {
return new ArrayList(getListProperty(AUTHORIZED_ORIGIN_URIS_PROPERTY_NAME));
}
@Override
public Application setAuthorizedOriginUris(List authorizedOriginUris) {
setProperty(AUTHORIZED_ORIGIN_URIS_PROPERTY_NAME, authorizedOriginUris);
save();
return this;
}
@Override
public Application addAuthorizedOriginUri(String authorizedOriginUri) {
List authorizedOriginUris = this.getAuthorizedOriginUris();
authorizedOriginUris.add(authorizedOriginUri);
setProperty(AUTHORIZED_ORIGIN_URIS_PROPERTY_NAME, authorizedOriginUris);
save();
return this;
}
@Override
public Account verifyPasswordResetToken(String token) {
String href = getPasswordResetTokensHref() + "/" + token;
Map props = new LinkedHashMap(1);
props.put("href", href);
PasswordResetToken prToken = getDataStore().instantiate(PasswordResetToken.class, props);
return prToken.getAccount();
}
/** @since 1.0.RC7 */
public OAuthPolicy getOAuthPolicy() {
return getResourceProperty(OAUTH_POLICY);
}
/** @since 1.0.RC */
@Override
public Account resetPassword(String passwordResetToken, String newPassword) {
Assert.hasText(passwordResetToken, "passwordResetToken cannot be empty or null.");
Assert.hasText(newPassword, "newPassword cannot be empty or null.");
String href = getPasswordResetTokensHref() + "/" + passwordResetToken;
Map props = new LinkedHashMap(1);
props.put("href", href);
DefaultPasswordResetToken instantiatedToken = (DefaultPasswordResetToken) getDataStore().instantiate(PasswordResetToken.class, props);
instantiatedToken.setPassword(newPassword);
PasswordResetToken createdPasswordResetToken =
getDataStore().create(href, instantiatedToken, PasswordResetToken.class);
return createdPasswordResetToken.getAccount();
}
@Override
public AuthenticationResult authenticateAccount(AuthenticationRequest request) {
AuthenticationRequestDispatcher dispatcher = Classes.newInstance(AUTHENTICATION_REQUEST_DISPATCHER_CLASS);
return dispatcher.authenticate(getDataStore(), this, request);
}
/** @since 1.0.beta */
@Override
public ProviderAccountResult getAccount(ProviderAccountRequest request) throws ResourceException {
return new ProviderAccountResolver(getDataStore()).resolveProviderAccount(getHref(), request);
}
@Override
public Group createGroup(Group group) {
Assert.notNull(group, "Group instance cannot be null.");
CreateGroupRequest request = Groups.newCreateRequestFor(group).build();
return createGroup(request);
}
@Override
public Group createGroup(CreateGroupRequest request) {
Assert.notNull(request, "Request cannot be null.");
final Group group = request.getGroup();
String href = getGroups().getHref();
if (request.isGroupOptionsSpecified()) {
return getDataStore().create(href, group, request.getGroupOptions());
}
return getDataStore().create(href, group);
}
public Account createAccount(Account account) {
Assert.notNull(account, "Account instance cannot be null.");
CreateAccountRequest request = Accounts.newCreateRequestFor(account).build();
return createAccount(request);
}
@Override
public Account createAccount(CreateAccountRequest request) {
Assert.notNull(request, "Request cannot be null.");
final Account account = request.getAccount();
String href = getAccounts().getHref();
char querySeparator = '?';
if (request.isRegistrationWorkflowOptionSpecified()) {
href += querySeparator + "registrationWorkflowEnabled=" + request.isRegistrationWorkflowEnabled();
querySeparator = '&';
}
if (request.isPasswordFormatSpecified()) {
href += querySeparator + "passwordFormat=" + request.getPasswordFormat();
}
if (request.isAccountOptionsSpecified()) {
return getDataStore().create(href, account, request.getAccountOptions());
}
return getDataStore().create(href, account);
}
@Override
public void delete() {
getDataStore().delete(this);
}
/** @since 0.9 */
@Override
public ApplicationAccountStoreMappingList getAccountStoreMappings() {
return getResourceProperty(ACCOUNT_STORE_MAPPINGS);
}
/** @since 0.9 */
@Override
public ApplicationAccountStoreMappingList getAccountStoreMappings(Map queryParams) {
ApplicationAccountStoreMappingList accountStoreMappings =
getAccountStoreMappings(); //safe to get the href: does not execute a query until iteration occurs
return getDataStore().getResource(accountStoreMappings.getHref(), ApplicationAccountStoreMappingList.class, queryParams);
}
/** @since 1.0.RC9 */
@Override
public ApplicationAccountStoreMappingList getAccountStoreMappings(ApplicationAccountStoreMappingCriteria criteria) {
ApplicationAccountStoreMappingList accountStoreMappings =
getAccountStoreMappings(); //safe to get the href: does not execute a query until iteration occurs
return getDataStore().getResource(accountStoreMappings.getHref(), ApplicationAccountStoreMappingList.class, (Criteria) criteria);
}
/** @since 0.9 */
@Override
public AccountStore getDefaultAccountStore() {
ApplicationAccountStoreMapping accountStoreMap = getResourceProperty(DEFAULT_ACCOUNT_STORE_MAPPING);
return accountStoreMap == null ? null : accountStoreMap.getAccountStore();
}
/** @since 0.9 */
@Override
public void setDefaultAccountStore(AccountStore accountStore) {
ApplicationAccountStoreMappingList applicationAccountStoreMappingList = getAccountStoreMappings();
boolean needToCreateNewStore = true;
for (ApplicationAccountStoreMapping accountStoreMapping : applicationAccountStoreMappingList) {
if (accountStoreMapping.getAccountStore().getHref().equals(accountStore.getHref())) {
needToCreateNewStore = false;
accountStoreMapping.setDefaultAccountStore(true);
accountStoreMapping.save();
setProperty(DEFAULT_ACCOUNT_STORE_MAPPING, accountStoreMapping);
break;
}
}
if (needToCreateNewStore) {
ApplicationAccountStoreMapping mapping = addAccountStore(accountStore);
mapping.setDefaultAccountStore(true);
mapping.save();
setProperty(DEFAULT_ACCOUNT_STORE_MAPPING, mapping);
}
save();
}
/** @since 0.9 */
@Override
public AccountStore getDefaultGroupStore() {
ApplicationAccountStoreMapping accountStoreMap = getResourceProperty(DEFAULT_GROUP_STORE_MAPPING);
return accountStoreMap == null ? null : accountStoreMap.getAccountStore();
}
/** @since 0.9 */
@Override
public void setDefaultGroupStore(AccountStore accountStore) {
ApplicationAccountStoreMappingList applicationAccountStoreMappingList = getAccountStoreMappings();
boolean needToCreateNewStore = true;
for (ApplicationAccountStoreMapping accountStoreMapping : applicationAccountStoreMappingList) {
if (accountStoreMapping.getAccountStore().getHref().equals(accountStore.getHref())) {
needToCreateNewStore = false;
accountStoreMapping.setDefaultGroupStore(true);
accountStoreMapping.save();
setProperty(DEFAULT_GROUP_STORE_MAPPING, accountStoreMapping);
break;
}
}
if (needToCreateNewStore) {
ApplicationAccountStoreMapping mapping = addAccountStore(accountStore);
mapping.setDefaultGroupStore(true);
mapping.save();
setProperty(DEFAULT_GROUP_STORE_MAPPING, mapping);
}
save();
}
/** @since 0.9 */
@Override
public ApplicationAccountStoreMapping createAccountStoreMapping(ApplicationAccountStoreMapping mapping) throws ResourceException {
String href = getAccountStoreMappingsHref();
return getDataStore().create(href, mapping);
}
/** @since 0.9 */
@Override
public ApplicationAccountStoreMapping addAccountStore(AccountStore accountStore) throws ResourceException {
ApplicationAccountStoreMapping accountStoreMapping = getDataStore().instantiate(ApplicationAccountStoreMapping.class);
accountStoreMapping.setAccountStore(accountStore);
accountStoreMapping.setApplication(this);
accountStoreMapping.setListIndex(Integer.MAX_VALUE);
return createAccountStoreMapping(accountStoreMapping);
}
/** @since 1.0.RC */
@Override
public ApiKey getApiKey(String id) throws ResourceException, IllegalArgumentException {
return getApiKey(id, new DefaultApiKeyOptions());
}
/** @since 1.0.RC */
@Override
public ApiKey getApiKey(String id, ApiKeyOptions options) throws ResourceException, IllegalArgumentException {
Assert.hasText(id, "The 'id' argument cannot be null or empty to get an api key.");
Assert.notNull(options, "options argument cannot be null.");
Assert.hasText(getHref(), "The application must have an href to get an api key.");
DefaultApiKeyCriteria criteria = new DefaultApiKeyCriteria();
criteria.add(new DefaultEqualsExpressionFactory(ID.getName()).eq(id));
if (!options.isEmpty() && options instanceof Expandable) {
Expandable expandable = (Expandable) options;
for (Expansion exp : expandable.getExpansions()) {
if ("tenant".equals(exp.getName())) {
criteria.withTenant();
}
if ("account".equals(exp.getName())) {
criteria.withAccount();
}
}
}
String href = getHref() + "/apiKeys";
ApiKeyList apiKeys = getDataStore().getResource(href, ApiKeyList.class, (Criteria) criteria);
Iterator iterator = apiKeys.iterator();
// we expect only one api key to be in the collection
return iterator.hasNext() ? iterator.next() : null;
}
// since 1.0.RC8
private void validateUri(String uri){
try {
URL url = new URL(uri);
} catch (MalformedURLException e) {
throw new IllegalArgumentException(INVALID_URI_FORMAT_MSG);
}
}
/** @since 0.9 */
private String getAccountStoreMappingsHref() {
//TODO enable auto discovery via Tenant resource (should be just /accountStoreMappings)
String href = "/accountStoreMappings";
// TODO: Uncomment out below when application's accountStoreMapping endpoint accepts POST request.
// AccountStoreMappingList accountStoreMappingList = getAccountStoreMappings();
// return accountStoreMappingList.getHref();
return href;
}
/** @since 1.0.RC */
@Override
public IdSiteUrlBuilder newIdSiteUrlBuilder() {
return new DefaultIdSiteUrlBuilder(getDataStore(), getHref());
}
/** @since 1.0.RC8 */
@Override
public SamlIdpUrlBuilder newSamlIdpUrlBuilder() {
return new DefaultSamlIdpUrlBuilder(getDataStore(), getHref(), this.getSamlPolicy().getSamlServiceProvider().getSsoInitiationEndpoint().getHref());
}
/** @since 1.0.RC */
@Override
public IdSiteCallbackHandler newIdSiteCallbackHandler(Object httpRequest) {
validateHttpRequest(httpRequest);
return new DefaultIdSiteCallbackHandler(getDataStore(), this, httpRequest);
}
/** @since 1.0.RC8 */
@Override
public SamlCallbackHandler newSamlCallbackHandler(Object httpRequest) {
validateHttpRequest(httpRequest);
return new DefaultSamlCallbackHandler(getDataStore(), this, httpRequest);
}
/** @since 1.0.0 */
public void sendVerificationEmail(VerificationEmailRequest verificationEmailRequest) {
Assert.notNull(verificationEmailRequest, "verificationEmailRequest must not be null.");
Assert.hasText(verificationEmailRequest.getLogin(), "verificationEmailRequest's email property is required.");
AccountStore accountStore = verificationEmailRequest.getAccountStore();
if(accountStore != null && accountStore.getHref() == null) {
throw new IllegalArgumentException("verificationEmailRequest's accountStore has been specified but its href is null.");
}
String href = getHref() + "/verificationEmails";
//We are passing a dummy return type (VerificationEmailRequest). It is not actually needed, but if we use the
//the two-parameters create(...) operation, we get an exception caused by an empty response body from the backend
getDataStore().create(href, (DefaultVerificationEmailRequest) verificationEmailRequest, DefaultVerificationEmailRequest.class);
}
@SuppressWarnings("unchecked")
private void validateHttpRequest(Object httpRequest) {
Assert.notNull(httpRequest);
Class httpRequestClass = httpRequest.getClass();
for (Class supportedClass : HTTP_REQUEST_SUPPORTED_CLASSES) {
if (supportedClass.isAssignableFrom(httpRequestClass)) {
return;
}
}
throw new IllegalArgumentException(String.format(HTTP_REQUEST_NOT_SUPPORTED_MSG, httpRequestClass.getName(),
HTTP_REQUEST_SUPPORTED_CLASSES.toString()));
}
/** @since 1.0.RC3 */
@Override
public ApplicationAccountStoreMapping addAccountStore(String hrefOrName) {
Assert.hasText(hrefOrName, "hrefOrName cannot be null or empty.");
AccountStore accountStore = null;
//Let's check if hrefOrName looks like an href. If so, we will also identify whether it refers to directory or a group
String[] splitHrefOrName = hrefOrName.split("/");
if (splitHrefOrName.length > 4) {
Class accountStoreType = null;
String[] splitApplicationHref = getHref().split("/");
if (splitHrefOrName.length == splitApplicationHref.length) {
if (splitHrefOrName[4].equals("directories")) {
accountStoreType = Directory.class;
} else if (splitHrefOrName[4].equals("groups")) {
accountStoreType = Group.class;
} else if (splitHrefOrName[4].equals("organizations")){
accountStoreType = Organization.class;
}
}
if (accountStoreType != null) {
try {
//Let's check if the provided value is an actual href for an existent resource
accountStore = getDataStore().getResource(hrefOrName, accountStoreType);
} catch (ResourceException e) {
//Although hrefOrName seemed to be an actual href value no Resource was found in the backend. So maybe
//this is actually a name rather than an href. Let's try to find a resource by name now...
}
}
}
if (accountStore == null) {
//Let's try to find both a Directory and a Group with the given name
Directory directory = getSingleTenantDirectory(Directories.where(Directories.name().eqIgnoreCase(hrefOrName)));
Group group = getSingleTenantGroup(Groups.where(Groups.name().eqIgnoreCase(hrefOrName)));
if (directory != null && group != null) {
//The provided criteria matched more than one Groups in the tenant, we will throw
throw new IllegalArgumentException("There are both a Directory and a Group matching the provided name in the current tenant. " +
"Please provide the href of the intended Resource instead of its name in order to univocally identify it.");
}
accountStore = (directory != null) ? directory : group;
}
if(accountStore != null) {
return addAccountStore(accountStore);
}
//We could not find any resource matching the hrefOrName value; we return null
return null;
}
/** @since 1.0.RC3 */
@Override
public ApplicationAccountStoreMapping addAccountStore(DirectoryCriteria criteria) {
Assert.notNull(criteria, "criteria cannot be null.");
Directory directory = getSingleTenantDirectory(criteria);
if (directory != null) {
return addAccountStore(directory);
}
//No directory matching the given information could be found; therefore no account store can be added. We return null...
return null;
}
/**
* @since 1.0.RC5
*/
@Override
public ApplicationAccountStoreMapping addAccountStore(OrganizationCriteria criteria) {
Assert.notNull(criteria, "criteria cannot be null.");
Organization organization = getSingleOrganization(criteria);
if (organization != null) {
return addAccountStore(organization);
}
//No organization matching the given information could be found; therefore no account store can be added. Return null.
return null;
}
/** @since 1.0.RC3 */
@Override
public ApplicationAccountStoreMapping addAccountStore(GroupCriteria criteria) {
Assert.notNull(criteria, "criteria cannot be null.");
Group group = getSingleTenantGroup(criteria);
if (group != null) {
return addAccountStore(group);
}
//No group matching the given information could be found; therefore no account store can be added. We return null...
return null;
}
/**
* @throws IllegalArgumentException if the criteria matches more than one Group in the current Tenant.
* @since 1.0.RC3
*/
private Directory getSingleTenantDirectory(DirectoryCriteria criteria) {
Assert.notNull(criteria, "criteria cannot be null.");
Tenant tenant = getDataStore().getResource("/tenants/current", Tenant.class);
DirectoryList directories = tenant.getDirectories(criteria);
Directory foundDirectory = null;
for (Directory dir : directories) {
if (foundDirectory != null) {
//The provided criteria matched more than one Directory in the tenant, we will throw
throw new IllegalArgumentException("The provided criteria matched more than one Directory in the current Tenant.");
}
foundDirectory = dir;
}
return foundDirectory;
}
/**
* @throws IllegalArgumentException if the criteria matches more than one Group in the current Tenant.
* @since 1.0.RC3
* */
private Group getSingleTenantGroup(GroupCriteria criteria) {
Assert.notNull(criteria, "criteria cannot be null.");
Tenant tenant = getDataStore().getResource("/tenants/current", Tenant.class);
DirectoryList directories = tenant.getDirectories();
Group foundGroup = null;
for (Directory directory : directories) {
GroupList groups = directory.getGroups(criteria);
//There cannot be more than one group with the same name in a single tenant. Thus, the group list will have either
//zero or one items, never more.
for (Group grp : groups) {
if(foundGroup != null) {
//The provided criteria matched more than one Groups in the tenant, we will throw
throw new IllegalArgumentException("The provided criteria matched more than one Group in the current Tenant.");
}
foundGroup = grp;
}
}
return foundGroup;
}
/**
* @throws IllegalArgumentException if the criteria matches more than one Group in the current Tenant.
* @since 1.0.RC5
* */
private Organization getSingleOrganization(OrganizationCriteria criteria) {
Assert.notNull(criteria, "criteria cannot be null.");
Tenant tenant = getDataStore().getResource("/tenants/current", Tenant.class);
OrganizationList organizations = tenant.getOrganizations(criteria);
Organization found = null;
int count = 0;
//There cannot be more than one organization with the same name in a single tenant. Thus, the group list will have either
//zero or one items, never more.
for (Organization org : organizations) {
count++;
found = org;
}
if(count > 1) {
//The provided criteria matched more than one Organizations in the tenant, we will throw
throw new IllegalArgumentException("The provided criteria matched more than one Organization in the current Tenant.");
}
return found;
}
/**
* @since 1.0.RC4.6
*/
@Override
public Application saveWithResponseOptions(ApplicationOptions responseOptions) {
Assert.notNull(responseOptions, "responseOptions can't be null.");
applyCustomDataUpdatesIfNecessary();
getDataStore().save(this, responseOptions);
return this;
}
/* @since 1.0.0 */
@Override
public OAuthClientCredentialsGrantRequestAuthenticator createClientCredentialsGrantAuthenticator() {
return new DefaultOAuthClientCredentialsGrantRequestAuthenticator(this, getDataStore());
}
/* @since 1.1.0 */
@Override
public OAuthStormpathSocialGrantRequestAuthenticator createStormpathSocialGrantAuthenticator() {
return new DefaultOAuthStormpathSocialGrantRequestAuthenticator(this, getDataStore());
}
/* @since 1.3.1 */
@Override
public OAuthStormpathFactorChallengeGrantRequestAuthenticator createStormpathFactorChallengeGrantAuthenticator() {
return new DefaultOAuthStormpathFactorChallengeGrantRequestAuthenticator(this, getDataStore());
}
/* @since 1.0.RC7 */
@Override
public OAuthPasswordGrantRequestAuthenticator createPasswordGrantAuthenticator() {
return new DefaultOAuthPasswordGrantRequestAuthenticator(this, getDataStore());
}
/* @since 1.0.RC7 */
@Override
public OAuthRefreshTokenRequestAuthenticator createRefreshGrantAuthenticator() {
return new DefaultOAuthRefreshTokenRequestAuthenticator(this, getDataStore());
}
/* @since 1.0.RC7 */
@Override
public OAuthBearerRequestAuthenticator createJwtAuthenticator() {
return new DefaultOAuthBearerRequestAuthenticator(this, getDataStore());
}
/* @since 1.0.RC8.2 */
public IdSiteAuthenticator createIdSiteAuthenticator() {
return new DefaultIdSiteAuthenticator(this, getDataStore());
}
@Override
public OAuthTokenRevocator createOAuthTokenRevocator() {
return new DefaultOAuthTokenRevocator(this, getDataStore());
}
/* @since 1.1.0 */
@Override
public AccountLinkingPolicy getAccountLinkingPolicy() {
return getResourceProperty(ACCOUNT_LINKING_POLICY);
}
@Override
public Application configureWithProperties(Map properties) {
setProperties(properties);
return this;
}
}