Copyright © 2013-2014 Stormpath, Inc. and contributors.
This project is open-source via the Apache 2.0 License.
For all additional information, please see the full Project Documentation.
This project requires Maven 3.2.1 and JDK 7 to build. Run the following:
> mvn install
This is a patch / bug-fix release that resolves a thread-safety issue in the data store that may impact some customers.
Stormpath Java SDK 1.0 Release Candidate 2
This is one of the big features that we wanted to ensure was supported in the SDK before 1.0 final: your own hosted white-labeled Identity Site, what we call an 'ID Site'!
You can have a 100% customizable white-labeled site, for example, https://id.awesomeapp.com
or
https://my.awesomeapp.com
, hosted and served securely by Stormpath. Your ID Site provides your end-users with a
hosted and secure registration, login, and password reset functionality, and completely hands-off integration with
Google and Facebook!.
Your white-labeled ID Site is beautiful and 'just works' out-of-the box and requires no development effort, but if you want to customize it in any way, you can easily fork our default GitHub repo and customize it as you desire, and we'll serve your fork securely just the same.
All that is required for this to work is that your application redirects your end-user to your secure ID Site URL and, when the user is done, can receive a redirect back to your application. This 1.0.RC2 release includes these two additional functions so you don't have to code that yourself.
See the Application interface's newIdSiteUrlBuilder method (for redirecting end-users to your ID Site) and the newIdSiteCallbackHandler method (for hanling the return reply from your ID Site) for code examples!
Stormpath Java SDK 1.0 Release Candidate
The Stormpath Java SDK can now act as an OAuth 2 Provider with full API Key management support!
You can now use the Java SDK to create and manage API Keys for your end-users so they can authenticate with your own
REST API. You can create, delete, enable/disable as many API Keys as you want for each of your end-user Account
resources. See the Account
interface's createApiKey*
and getApiKeys*
methods.
Now for the really powerful stuff: the Stormpath Java SDK implements OAuth2 provider functionality. Your end-users can
use these API Keys to make OAuth 2 requests to your REST API, and the Stormpath Java SDK will authenticate the requests
via OAuth as you wish. This includes both OAuth 2 access token requests (e.g. the /oauth/token
endpoint) as well as
resource requests (e.g. /movies/1234
). At no point do you ever need to see, touch, or write OAuth code!
The Stormpath SDK does it for you.
See the Application
interface's authenticateApiRequest
and authenticateOauthRequest
methods for lots of detailed
information.
All resource mutator methods can now be chained for less verbose object construction. For example, instead of:
Account account = client.instantiate(Account.class);
account.setGivenName("John");
account.setGivenName("Smith");
account.setEmail("[email protected]");
account.save();
one might choose to write instead:
client.instantiate(Account.class)
.setGivenName("John").setSurname("Smith").setEmail("[email protected]").save();
The Client
and Tenant
interfaces now both extend a new TenantActions
interface that represents common
tenant behavior. This allows you to perform this common tenant behavior directly via a Client
instance without
having to call the intermediate client.getCurrentTenant()
method first.
For example, instead of:
client.getCurrentTenant().createApplication(anApp);
you may now write:
client.createApplication(anApp);
which is likely more intuitive.
Resetting an end-user's password via password reset token can now be done in a single method call. Just provide the reset token and the new password, and that's it.
- Issue 46: Application#setDefault*StoreMapping IT failure
- Issue 48: OAuth provider support with API Key management!
- Issue 52: Removed unnecessary Provider setters
- Issue 54: AuthenticationResult must not extend Resource
- Issue 55: Account's password can now be reset along with the password reset token, in one API call
- Issue 56: Method chaining for Resources.
- Issue 58: Allow a
Client
instance to directly perform commonTenant
actions.
- Added Provider integration: Google and Facebook are supported.
This beta release contains a few backwards-incompatible changes, we strive to keep them minimal.
- ClientBuilder was previously in charge of constructing the ApiKey. Now, the ApiKey is built through a new ApiKeyBuilder interface which can be instantiated via the new
com.stormpath.sdk.client.ApiKeys
utility class. ApiKeyBuilder provides a nice fluent builder API. Once the ApiKey is built, it can be set to the Client by means of the ClientBuilder instance.
- Added the possibility to specify AccountStore during authentication.
- Issue 36: Client version is now being obtained from version.properties file
This is a prep release for the 1.0 final release, and we are finalizing the 1.0 API. As a result, this alpha release contains a few backwards-incompatible changes, but we have tried to keep them a minimum. As we have tried very hard to do during 0.x, 1.x will continue to enforce semantic versioning practices so there are little surprises.
- Client and ClientBuilder were previously concrete classes - they are now interfaces. A
com.stormpath.sdk.client.Clients
utility class has been added with utility methods for creating clients, providing a nice fluent builder API. This retains a creation/builder pattern in use across the rest of the client API.
- Issue 16: Allow client to use basic authentication
- Backwards-incompatible change: com.stormpath.sdk.impl.http.support.SignatureException has been replaced by com.stormpath.sdk.impl.http.support.RequestAuthenticationException
- New method for Account: isMemberOfGroup(String hrefOrName)
This is a bugfix point release that resolves 3 issues:
- Issue 30: Custom data updates are not cached when calling account/group save()
- Issue 28: ResourceException getMessage() should return a more descriptive message
- Issue 31: Provide more detailed ResourceException messages (duplicate of Issue #28).
This is a bugfix point release that resolves 1 issue:
- Issue 25: account.addGroup and group.addAccount do not work
This is a milestone / new feature release.
Our most requested feature is now available via the Stormpath Java SDK!
You now have the ability to create, update, delete up to 10 Megabytes of your own custom data per Account
or Group
stored within Stormpath. This is a big deal: any account or group information that you can think of specific to your application(s) can now be stored directly with the account or group. This allows you to completely remove user tables within your application if you desire.
Read the Custom Data announcement and the Custom Data REST API documentation for more information and how to safely use Custom Data in your own applications.
Custom Data
is a SDK Resource: you can save, update and delete it like any other. But it is also a java.util.Map<String,Object>
implementation:
CustomData data = account.getCustomData();
data.put("favoriteColor", "blue");
data.remove("favoriteHobby");
data.save();
Because CustomData
extends Map<String,Object>
, you can store whatever data you want, but NOTE:
The data MUST be JSON-compatible. This means you can store primitives, and Maps, Arrays, Collections, nested as deep as you like. Ensure the objects you persist can be marshalled to/from JSON via Jackson (what the Stormpath Java SDK uses for JSON marshalling). Also a single Custom Data
resource must be less than 10 Megabytes in size.
Custom Data is a resource like any other - you can save()
modifications and delete()
it if you like. But, because it it has a 1-to-1 correlation with an owning Account
or Group
, it is a little extra special: you can also save, update and delete Custom Data just by saving the owning account or group.
For example, let's say you wanted to create a Starfleet account for Captain Jean-Luc Picard. Because Stormpath has no knowledge of Star Trek-specific needs, we can store this in the account's Custom Data resource:
Application application = getApplication(); //obtain the app instance however you wish
Account account = client.instantiate(Account.class);
account.setGivenName("Jean-Luc");
account.setSurname("Picard");
account.setEmail("[email protected]");
account.setPassword("Changeme1!");
//let's store some application-specific data:
CustomData data = account.getCustomData();
data.put("rank", "Captain");
data.put("birthDate", "2305-07-13");
data.put("birthPlace", "La Barre, France");
data.put("favoriteDrink", "Earl Grey tea (hot)");
application.createAccount(account);
Notice how we did not call data.save()
- creating the account (or updating it later via save()
) will automatically persist the account's customData
resource. The account 'knows' that the custom data resource has been changed and it will propogate those changes automatically when you persist the account.
Groups work the same way - you can save a group and it's custom data resource will be saved as well.
NOTE: Just remember, if you have any secure data or information you don't want searchable, ensure you encrypt it before saving it in an account or group's custom data resource. Read the Custom Data announcement for usage guidelines.
As a convenience, you may now create account
and group
resources directly via an application, without first needing to obtain the intermediate directory or group where they will be persisted:
Application application = getApplication(); //obtain the app instance however you wish
Account account = client.instantiate(Account.class);
account.setGivenName("John");
account.setSurname("Smith");
account.setEmail("[email protected]");
account.setPassword("Changeme1!");
application.createAccount(account);
You can also use the CreateAccountRequest
concept to control other account creation directives. For example, using the Fluent API:
import static com.stormpath.sdk.account.Accounts.*;
...
account = application.createAccount(newCreateRequestFor(account).setRegistrationWorkflowEnabled(true).build());
Again, this is a convenience: The account will be routed to (and created in) the application's designated default account store, or throw an error if there is no designated account store.
Because accounts are not 'owned' by applications (they are 'owned' by a directory), this will not make application 'private' accounts - it is merely a convenience mechanism to reduce the amount of work to create an account that may use a particular application.
Similar to accounts, as a convenience, you may create group
resources directly via an application without first needing to obtain the intermediate directory where the group will be persisted:
Application application = getApplication(); //obtain the app instance however you wish
Group group = client.instantiate(Group.class);
group.setName("Directory-unique name here");
application.createGroup(group);
You can also use the CreateGroupRequest
variant to control other group creation directives. For example, using the fluent API:
import static com.stormpath.sdk.group.Groups.*;
...
group = application.createGroup(newCreateRequestFor(group).withResponseOptions(options().withCustomData()).build());
Remember, this is a convenience: The group will be routed to (and created in) the application's designated default group store, or throw an error if there is no designated group store.
Because groups are not 'owned' by applications (they are 'owned' by a directory), this will not make application 'private' groups - it is merely a convenience mechanism to reduce the amount of work to create a group accessible to a particular application.
You may now create and delete 'Cloud' (natively hosted) directories in Stormpath with the Stormpath Java SDK. LDAP and Active Directory 'Mirrored' directories must still be created in the Stormpath Admin Console UI. For example:
Directory dir = client.instantiate(Directory.class);
dir.setName("My new 'cloud' Directory");
dir = client.getCurrentTenant().createDirectory(dir);
...
//delete it when no longer useful
dir.delete();
Account Store Mappings are useful in more advanced usages of Stormpath, for example, if you have more than one directory (or group) to assign to an application to create a merged user base for the application.
The Java SDK now allows you to add, remove, re-order and generally manage an Application's account store mappings for these more advanced use cases. See the JavaDoc for the AccountStoreMapping
resource and the following Application
methods:
AccountStoreMappingList getAccountStoreMappings();
AccountStoreMappingList getAccountStoreMappings(Map<String, Object> queryParams);
AccountStoreMappingList getAccountStoreMappings(AccountStoreMappingCriteria criteria);
AccountStore getDefaultAccountStore();
void setDefaultAccountStore(AccountStore accountStore);
AccountStore getDefaultGroupStore();
void setDefaultGroupStore(AccountStore accountStore);
AccountStoreMapping createAccountStoreMapping(AccountStoreMapping mapping) throws ResourceException;
AccountStoreMapping addAccountStore(AccountStore accountStore) throws ResourceException;
This is a bugfix point release that resolves 1 issue:
- Issue #12 application.authenticateAccount fails if caching is enabled
Collection Resource iteration previously only represented the first page in a collection. Iteration now transparently iterates over the entire collection, automatically requesting new pages from the server as necessary. For example:
AccountList accounts = application.getAccounts();
//iterate over the entire account collection:
for (Account account : accounts) {
//do something with the account
}
The SDK now has full caching support, utilizing a CacheManager interface (that produces/manages Cache instances). If enabled, this improves performance by reducing round-trips to the Stormpath API servers.
An out-of-the-box production-grade CacheManager implementation - complete with default and per-region TTL/TTI configuration - may be configured for single-JVM applications. Single-JVM app example config:
import static com.stormpath.sdk.cache.Caches.*;
...
Client client = Clients.builder()
.setApiKey(ApiKeys.builder()
.setFileLocation(System.getProperty("user.home") + "/.stormpath/apiKey.properties")
.build()
)
.setCacheManager(newCacheManager()
.withDefaultTimeToLive(1, TimeUnit.DAYS) //general default
.withDefaultTimeToIdle(2, TimeUnit.HOURS) //general default
.withCache(forResource(Account.class) //Account-specific cache settings
.withTimeToLive(1, TimeUnit.HOURS)
.withTimeToIdle(30, TimeUnit.MINUTES))
.withCache(forResource(Group.class) //Group-specific cache settings
.withTimeToLive(2, TimeUnit.HOURS))
.build() //build the CacheManager
)
.build(); //build the Client
Multi-JVM applications (an application deployed across multiple JVMs) would likely want to use a distributed/clustered coherent Cache product like Hazelcast, Ehcache+TerraCotta, Oracle Coherence, Gigaspaces, etc. To leverage these caching products, you must implement the two interfaces (CacheManager
and Cache
) to delegate to your Caching provider API of choice, and you're on your way. For example:
CacheManager cacheManager = new CacheManagerImplementationThatUsesMyPreferredCachingProduct();
Client client = Clients.builder()
.setApiKey(ApiKeys.builder()
.setFileLocation(System.getProperty("user.home") + "/.stormpath/apiKey.properties")
.build()
)
.setCacheManager(cacheManager);
.build();
In both cases, the Stormpath Java SDK will store resource data in separate cache regions. Each region is named after a resource interface for which it caches data, e.g. "com.stormpath.sdk.account.Account"
, allowing for custom caching rules per resource type. This gives you finer control of resource caching behavior based on your preferences/needs.
Two new query mechanisms were introduced - you choose which you want to use based on your preference and/or JVM language.
- Fluent and type-safe query DSL: If you're using a type-safe language, you will find this convenient, especially when using an IDE that auto-completes. You'll find writing valid queries fast! For example:
import static com.stormpath.sdk.account.Accounts.*; ... application.getAccounts(where( surname().containsIgnoreCase("Smith")) .and(givenName().eqIgnoreCase("John")) .orderBySurname().descending() .withGroups(10, 10) //eager fetching .offsetBy(20).limitTo(25)); //pagination
- Map-based query methods. These are not type safe, but might be desirable for some developers, maybe those using dynamically typed languages. The map key/value pairs are simply REST API query parameters and values. For example, the same results of the above fluent query could be achieved as follows in Groovy:
application.getAccounts [surname: '*Smith*', givenName: 'John', orderBy: 'surname desc', expand: 'groups(offset:10,limit:10)' offset: 20, limit: 25]
JavaDoc has been improved significantly. But please don't hesitate to send us a Pull Request with fixes or enhancements!