Tynamo-federatedaccounts is an add-on to tapestry-security module and provides and API and components for doing federated authentication, i.e. authenticating (your application) users with a third-party, such as Facebook, Twitter or Google. The most well-known protocol for it is probably Oauth. However, the module is purposefully not named as "tynamo-oauth" or similar, since the provided interfaces are designed for any federated accounts (where you need to "bridge" more than one account together), regardless of protocol. Besides Oauth, LDAP and custom remote authentication servers are obvious use cases. The module provides an authenticating realm for each specific third-party and required components and pages to authenticate via a particular federated authentication scheme. The module is designed to be as light-weight and non-invasive as possible with minimal amount of configuration required. For example, for enabling simple authentication with Facebook in your (Hibernate-based web) application, you only need to provide the following configuration:
The User class above is your own persistent type, or in the case of Hibernate/JPA, an @Entity. All types you are contributing to FederatedAccountService need to implement the interface org.tynamo.security.federatedaccounts.FederatedAccount. FederatedAccount interface is shown below:
Depending on the FederatedAccountService used, you don't necessarily need to provide any meaningful implementation for federate(...) operation, but it's provided in case you want to merge/update some account properties. See the example implementation for ideas.
FederatedAccountService is a lightweight interface, providing a bridge between your local user accounts and remote accounts. The only operation in FederatedAccountService is:
The operation is designed to be invoked after a remote authentication has succeeded. "remotePrincipal" parameter is the username/userid in the remote system and the last parameter is an optional object describing the remote account. The current Facebook realm is using RestFB and returns RestFB User object as the remoteAccount. DefaultHibernateFederatedAccountServiceImpl tries to obtain the configured entity for this realm (see the configuration above) and saves or updates the entity after calling its federate(...) operation.
FederatedAccounts module requires that FederatedAccountService interface is bound to an existing service, but doesn't bind to any by default. This is so you can provide a custom implementation for FederatedAccountService, using your own persistence model.
To load tynamo-federatedaccounts module, specify the following in your application pom.xml:
Note that for a snapshot version, you need to use the following repository:
First, create a Facebook application. Configure FacebookRealm with the given credentials:
What should you customize and why?
- If you are not using hibernate as your persistence framework...
-> provide a custom FederatedAccountService implementation
- If you are handling your own transactions...
-> set autoCommit to false (document properly)
- If you are using Hibernate, but need to merge local accounts with remote accounts matching a specific property...
-> override : DefaulHibernateFederatedAccountServiceImpl.findLocalAccount(Class<?> entityType, String realmName, Object remotePrincipal, Object remoteAccount)
- If you are adding/updating (i.e. cache) property values from remote account to local account...
-> implement the required logic in FederatedAccount.federate(String realmName, Object remotePrincipal, Object remoteAccount)
- If you are implementing your own remote account provider...
-> See the current FacebookRealm implementation, FacebookOauth page and FacebookSignIn component and related classes for examples (and contribute back if it's generally useful!)
Check out more examples from our full-featured functional tests or a simple, live demonstration with the default Facebook authentication in action, running on GAE. Note that (a free account on) Google App Engine (GAE) can be pretty slow to cold boot those JVMs, so if things don't load properly the first time around, just refresh the page.