Java EE Security and JSON Binding are two new APIs in the Java EE 8 release. The security API provides consistencies between containers with a simple annotation-driven model while JSON Binding completes Java EEs JSON APIs and is a real alternative to Jackson and Gson. In this presentation, I will walk through coding examples from both APIs and by the end of the presentation, you will understand how these two new APIs add to the advancement of the Java EE platform.
7. Security 1.0 API
Objective
◦ Simplify, standardise and modernise
◦ JACC, JASPIC and proprietary APIs
◦ Security EG to resolve issues
8. Security 1.0 API
Historical issues
• Inconsistent across containers
• Servlets provide
HttpServletRequest.isUserInRole(String role)
• EJBs provide
EJBContext.isCallerInRole(String roleName)
• Existing security mechanisms tricky
• Limited portable authentication
• No standard identity store management
• No support for custom authentication rules
9. Parallel thread
◦ Enable developers
◦ APIs for authentication, identity stores, roles and permissions across containers
◦ Java EE 8 Survey Final Results
◦ 11% security simplications
Source: https://blogs.oracle.com/theaquarium/java-ee-8-survey-final-results
10. Specification focus
◦ Relevant to cloud native applications
◦ An API for Web Authentication Mechanism
◦ A security context API
◦ An identity store API
◦ Simplify, standardise and modernise
◦ Web authentication has been modernised
◦ New security context API standardizes authentication
◦ Identity store abstraction to simplifies the use of identity stores.
@BasicAuthenticationMechanismDefinition
SecurityContext.getCallerPrincipal()
IdentityStore
11. Annotation driven authentication mechanism
◦ Simplified and standardised way to implement security
◦ HttpAuthenticationMechanism interface
◦ @BasicAuthenticationMechanismDefinition
◦ @FormAuthenticationMechanismDefinition
◦ @CustomFormAuthenticationMechanismDefinition
◦ Replicate Servlet 4 (section 13.6) authentication
◦ Developer can implement custom authentication
12. @BasicAuthenticationMechanismDefinition
◦ Triggers HTTP basic authentication (Servlet section 13.6.1)
◦ Optional realm name sent via the WWW-Authenticate header
@BasicAuthenticationMechanismDefinition(realmName = "user-realm")
@WebServlet("/user")
@DeclareRoles({"admin", "user", "demo"})
@ServletSecurity(@HttpConstraint(rolesAllowed = "user"))
public class UserServlet extends HttpServlet {
// Servlet Code
}
13. @FormAuthenticationMechanismDefinition
◦ Triggers form based authentication (Servlet section 13.6.3)
◦ loginToContinue option must be set
◦ Provides “login to continue” functionality
◦ useForwardToLogin = true/false
◦ useForwardToLoginExpression = "${appConfigs.forward}"
@FormAuthenticationMechanismDefinition(
loginToContinue = @LoginToContinue(
loginPage = "/login-servlet",
errorPage = "/login-servlet-fail"
)
)
@ApplicationScoped
public class ApplicationConfig {
// Config Code
}
14. @CustomFormAuthenticationMechanismDefinition
◦ provides options for configuring a custom login form
@CustomFormAuthenticationMechanismDefinition(
loginToContinue = @LoginToContinue(
loginPage = "/login.do"
errorPage = "/error.do"
)
)
Backing bean
<form jsf:id="form">
Username <input jsf:id="username" type="text" jsf:value="#{loginBean.username}"/>
Password <input jsf:id="password" type="password" jsf:value="#{loginBean.password}"/>
<input type="submit" value="Login" jsf:action="#{loginBean.login}"/>
</form>
@FacesConfig(version = JSF_2_3)
@Named
@RequestScoped
public class LoginBean {
public void login() {
// login logic
}
}
◦ Only option configured
Login JSF
15. Custom HttpAuthentictionMechanism
◦ Develop your own implementation
◦ Must be implemented as CDI bean with @ApplicationScope
◦ validateRequest() authenticates an HTTP request from a caller
◦ secureResponse() secures the HTTP response message
◦ cleanSubject() clears the subject of provided principals and credentials
◦ HttpServletRequest, HttpServletResponse, and
HttpMessageContext
16. Custom HttpAuthentictionMechanism
◦ Example implementation
@ApplicationScoped
public class CustomAuthenticationMechanism implements HttpAuthenticationMechanism {
@Inject
private IdentityStoreHandler idStoreHandler;
@Override
public AuthenticationStatus validateRequest(
HttpServletRequest req,
HttpServletResponse res,
HttpMessageContext msg) {
String username = ...get username from HttpRequest...
String password = ...get password from HttpRequest...
CredentialValidationResult result = idStoreHandler.validate(
new UsernamePasswordCredential(username, password));
return msg.notifyContainerAboutLogin(result);
}
}
17. Remember Me Feature
◦ Class level @RememberMe annotation
@RememberMe(
cookieMaxAgeSeconds = 3600
)
◦ cookieMaxAgeSeconds: Life of the remember me cookie
◦ cookieMaxAgeSecondsExpression: EL version of cookieMaxAgeSeconds
◦ cookieSecureOnly: accessed cookie via secure means
◦ cookieSecureOnlyExpression: EL version of cookieSecureOnly
◦ cookieHttpOnly: sent with HTTP requests only
◦ cookieHttpOnlyExpression: EL version cookieHttpOnly
◦ cookieName: The cookie’s name
◦ isRememberMe: Switches “remember me” on or off
◦ isRememberMeExpression: EL version of isRememberMe
18. Identity store abstraction
◦ IdentityStore interacts with identity stores to retrieve group memberships
◦ Intended use with HttpAuthenticationMechanism implementations
◦ Containers are not tiered to the IdentityStore
◦ Instances of the IdentityStore are handled via the
IdentityStoreHandler
◦ validate() method invokes IdentityStore methods and aggregates
result
◦ Create your own identity store by implementing the IdentityStore
@Inject
private IdentityStoreHandler idStoreHandler;
public interface IdentityStoreHandler {
CredentialValidationResult validate(Credential credential);
}
19. Default identity store implementation
◦ Default implementation of IdentityStoreHandler should suffice
◦ Authenticate against multiple identity stores
◦ Aggregate result as a CredentialValidationResult
21. @DataBaseIdentityStoreDefinition
◦ RDBMS identity store configured by @DataBaseIdentityStoreDefinition
◦ Configurations are fairly self-explanatory, with 9 config options
◦ NOTE: priority specifies order in case of multiple identity stores
@DatabaseIdentityStoreDefinition(
dataSourceLookup = "${'java:global/permissions_db'}",
callerQuery = "#{'select password from caller where name = ?'}",
groupsQuery =
"select group_name from caller_groups where caller_name = ?",
hashAlgorithm = PasswordHash.class,
priority = 10
)
@ApplicationScoped
@Named
public class ApplicationConfig { }
22. @LdapIdentityStoreDefinition
◦ LDAP identity store configured by @LdapIdentityStoreDefinition
◦ Configurations are fairly self-explanatory, 24 config options
◦ NOTE: priority specifies order in case of multiple identity stores
@LdapIdentityStoreDefinition(
url = "ldap://localhost:33389/",
callerBaseDn = "ou=caller,dc=jsr375,dc=net",
groupSearchBase = "ou=group,dc=jsr375,dc=net" ,
priority = 20
)
@DeclareRoles({"admin", "user", "demo"})
@WebServlet("/admin")
public class AdminServlet extends HttpServlet { }
23. IdentityStore interface
◦ Custom identity store implement IdentityStore interface
◦ Four methods
◦ CredentialValidationResult validate(Credential)
◦ Set<String> getCallerGroups(CredentialValidationResult)
◦ Set<ValidationType> validationTypes() returns set of VALIDATE
and/or PROVIDE_GROUPS
◦ int priority()
◦ All methods have default implementations
24. Multiple identity store interface
◦ Multiple IdentityStore implementations are handled by
the IdentityStoreHandler
◦ Identity stores called in accordance with declared capabilities and priority
◦ Two phase interation: 1st validates user 2nd gather group membership
◦ Caller validated by one IdentityStore and group membership list built from
another
1st iteration 2nd iteration
25. Security Context
◦ Consistent approach to security across the servlet and EJB containers
◦ Entry point for programmatic security and is injectable
◦ getCallerPrincipal() container-specific principal
◦ getPrincipalsByType() returns all Principals of the specified type
◦ isCallerInRole() determines if the caller is included in the role
◦ hasAccessToWebResource() determines caller access to the given recourse
◦ authenticate() triggers start/continuation of HTTP authentication with
caller. Requires valid servlet context
26. Security Context
boolean role = securityContext.isCallerInRole("admin");
name = securityContext.getCallerPrincipal().getName();
Set<CustomPrincipal> customPrincipals =
securityContext.getPrincipalsByType(CustomPrincipal.class);
for (CustomPrincipal customPrincipal : customPrincipals) {
response.getWriter().write((customPrincipal.getName()));
}
@Inject
private SecurityContext securityContext;
◦ Inject the SecuirtyContext
◦ Test user’s role membership
◦ Retrieve the caller principle
◦ Retrieve all CustomPrinciple
32. JSON serialiser and deserialiser
◦ Instance of Jsonb jsonb = JsonbBuilder.create()
◦ toJson() pass it the Java instance
Book book = new Book("SHDUJ-4532", "Fun with Java", "Alex Theedom");
String bookJson = JsonbBuilder.create().toJson(book);
◦ fromJson() pass it the JSON doc and Java class
String json = "{"author":"Alex Theedom"," +
""id":"SHDUJ-4532"," +
""title":"Fun with Java"}";
Book book = JsonbBuilder.create().fromJson(json, Book.class);
33. JSON Binding customisation
◦ Default mapping for simple scenarios
◦ Annotation model
◦ Runtime configuration
◦ Advanced customisation
◦ Adapters and custom serializers/deserializers
@JsonbNumberFormat("#0.00")
private Float price;
JsonbBuilder.create(new JsonbConfig().withNullValues(true));
34. JSON Binding customisation
◦ Annotation model
◦ Runtime configuration
@JsonbNillable
@JsonbPropertyOrder(PropertyOrderStrategy.REVERSE)
public class Book {
@JsonbProperty("cost")
@JsonbNumberFormat("#0.00")
private Float price;
}
JsonbConfig jsonbConfig = new JsonbConfig()
.withPropertyNamingStrategy(
PropertyNamingStrategy.LOWER_CASE_WITH_DASHES)
.withNullValues(true)
.withFormatting(true);
Jsonb jsonb = JsonbBuilder.create(jsonbConfig);
35. Customize object creation
◦ No argument public constructors
public class Magazine {
private String title;
private Author authorName;
@JsonbCreator
public Magazine(@JsonbProperty("bookTitle") String title,
@JsonbProperty("firstName") String firstName,
@JsonbProperty("surname") String lastName) {
this.title = title;
this.authorName = new Author(firstName, lastName);
}
}
{
"firstName": "Alex",
"surname": "Theedom",
"bookTitle": "Fun with JSON-B"
}
36. JSON Binding adapters
◦ Custom object creation with JsonbAdapter
public class BookletAdapter implements JsonbAdapter<Booklet, JsonObject> {
@Override
public JsonObject adaptToJson(Booklet booklet) {
return Json.createObjectBuilder()
.add("title", booklet.getTitle())
.add("firstName", booklet.getAuthor().getFirstName())
.add("lastName", booklet.getAuthor().getLastName())
.build();
}
@Override
public Booklet adaptFromJson(JsonObject json) {
Booklet booklet = new Booklet(json.getString("title"),
new Author(json.getString("firstName"),
json.getString("lastName")));
return booklet;
}
}
JsonbConfig config = new JsonbConfig()
.withAdapters(new BookletAdapter());
37. JSON Binding adapters
◦ Mark with @JsonbTypeAdapter
public class Author {
@JsonbTypeAdapter(FirstNameAdapter.class)
private String firstName;
}
public class FirstNameAdapter implements JsonbAdapter<String, JsonValue> {
@Override
public JsonValue adaptToJson(String fullName) {
return Json.createValue(fullName.subSequence(0, 1).toString());
}
@Override
public String adaptFromJson(JsonValue json) {
return json.toString();
}
}
38. JSON Binding custom serializers and deserializers
◦ Lowest level of customisation
public class BookSerializer implements JsonbSerializer<Book> {
@Override
public void serialize(Book book,
JsonGenerator generator, SerializationContext ctx) {
generator.writeStartObject();
generator.write("id", "QWE-123-RTS");
generator.write("title", book.getTitle());
generator.write("firstName", book.getAuthor().split(" ")[0]);
generator.write("lastName", book.getAuthor().split(" ")[1]);
generator.writeEnd();
}
}
39. JSON Binding custom serializers and deserializers
public class BookDeserializer implements JsonbDeserializer<String> {
@Override
public String deserialize(JsonParser parser,
DeserializationContext ctx, Type rtType) {
while (parser.hasNext()) {
JsonParser.Event event = parser.next();
if (event == JsonParser.Event.KEY_NAME) {
String keyName = parser.getString();
if (keyName.equals("id")) {
return ctx.deserialize(String.class, parser);
}
}
parser.next();
}
return "";
}
}
JsonbConfig config = new JsonbConfig()
.withDeserializers(new BookDeserializer())
.withSerializers(new BookSerializer());
@JsonbTypeDeserializer(BookDeserializer.class)
public class Booklet{}
41. Round-up
◦ Security has a consistence approach
◦ Highly customisable with sensible defaults
◦ Developer is empowered
◦ JSON Processing is now up to date
◦ JSON-B’s standardizes the transformation of Java and JSON
◦ Two customisation models with advanced customisation
43. Java EE 8: Only What’s New
bit.ly/CodeEuropeConf
Special price $9.95
Includes:
JSON Binding 1.0
Security 1.0
Servlet 4.0
Bean Validation 2.0
CDI 2.0
JAX-RS 2.1
JSF 2.3
JSON Processing 1.1 and JPA 2.2.
Editor's Notes
Hi My name is Alex Theedom. I am a Java EE consultant and trainer. I regularly blog at readlearncode.com about Java EE and you can following me on my twitter handle @alextheedom
I have authored and published Java EE courses over at lynda.com that cover
RESTful services with JAX-RS
WebSocket programming
Bean Validation
JSON processing
And soon to be released CDI 2.0 and Java EE design patterns and architecture
I have also published a book covering what's new in Java EE 8 and its available for a special conference discount at only $9.95, just follow the bitly link you see on the screen.
In this presentation I will start with a look at the new security API, then I will look at JSON Binding and dive into how to use this great new API, and I will finish with a round up and then you have the chance to ask some questions.
The primary motivations for the new Java EE Security API were to simplify, standardise and modernise the way security concerns are handled across containers and implementations.
Experienced Java EE developers know there are many different security mechanisms available, including JACC, JASPIC and proprietary security APIs and configuration management provided by each vendor’s implementation of Java EE containers.
None of these security mechanism are perfect and present their own problems regarding ease of use and consistency across containers and vendors.
So the security specification expert group set out to resolved some specific issues.
So what are the specific problems the Security API is designed to solve?
The EJB and servlet containers define similar security related APIs but with subtly different syntax.
For example, the servlet API defines a method that checks a user belongs to a given role as: HttpServletRequest.isUserInRole(String role)
while EJBs perform the same check by calling: EJBContext.isCallerInRole(String roleName).
Additionally,
Existing security mechanisms like JACC are tricky to implement and JASPIC can be difficult to use correctly. Neither of these mechanisms take full advantage of modern Java EE programming features such as CDI.
Also, there are limited portable ways for controlling how authentication happens on the backend across containers.
And there is no standard support for managing identity stores or the configuration of roles and permissions.
Neither is there a standard support for deploying custom authentication rules.
An important thread running parallel to the specification’s principal aims, is to empower developers to manage and control security themselves by defining portable APIs for authentication, identity stores, roles and permissions and authorizations across containers.
A security specification that resolve these problems was given force by the strong community support demonstrated in a Java EE 8 survey carried out by Oracle in early 2014.
As you can see, the simplification of security was high in the minds of the survey’s respondents.
As a result, the specification focuses on technology relevant to cloud native applications and includes the following new features are:
an API for Web Authentication Mechanism
a security context API and
an Identity store API.
And these features are brought together with standardise security terminology.
So as you discovered in the previous slide the primary motivations for this new API were to simplify, standardise and modernise the way security concerns are handled across containers and implementations. And they have done a great job.
The configuration of web authentication has been modernised thanks to three new annotations that make web.xml file declaration redundant.
The new security context API standardizes the way the servlet and EJB container perform authentication and
The new Identity store abstraction simplifies the use of identity stores.
Ok so, let’s jump right in and look at the new web authentication mechanism.
This API provides a simplified and standardised way to implement security in a Java EE application.
Thanks to the HttpAuthenticationMechanism interface which is at the heart of the new web application security mechanisms and represents an HTTP authentication.
The Security API comes with three built-in implementations. The built-in authentication mechanisms are trigger with the use of one of these annotations.
@BasicAuthenticationMechanismDefinition @FormAuthenticationMechanismDefinition
@CustomFormAuthenticationMechanismDefinition
They replicate the functionality of the classic HTTP basic authentication, form based authentication and custom form based authentication already available in the servlet container and specified in Servlet 4.0 (section 13.6).
In addition to the built in implementation the developer can implement custom implementations that support specific protocols and authentication tokens.
I want to spend some time looking at each one of these mechanisms.
The @BasicAuthenticationMechanismDefinition annotation triggers the use of the HTTP basic authentication mechanism
It has one optional parameter, which is the realm name; this specifies the name of the realm that will be sent via the HTTP authenticate header.
You can see in the code snippet here how to trigger the use of the HTTP basic authentication for the realm name `user-realm`.
The @FormAuthenticationMechanismDefinition annotation provokes form based authentication.
It has only one configuration option that must be set. The loginToContinue option accepts a configured @LoginToContinue annotation, which allows the application to provide “login to continue” functionality.
In this code example the login page is specified as /login-servlet, if authentication fails, flow is passed to the error page at /login-servlet-fail.
@FormAuthenticationMechanismDefinition(
Two further options can be set.
The manner of reaching the login page can be set to either “forward” or “redirect” and is set by specifying `true` or `false` to the `useForwardToLogin` option, by default it is `true`.
Alternatively the value can be set via an EL expression passed to the option useForwardToLoginExpression
The @CustomFormAuthenticationMechanismDefinition annotation provides options for configuring a custom login form.
In this code snippet you can see that the login page is specified as login.do.
And this is the login.do JSF page, which is supported by a login backing bean.
<form jsf:id="form"></form>
@Named
@RequestScoped
public class LoginBean {}
Now, the backing bean will use a `SecurityContext` instance to perform authentication. I have not shown this cod here as I will be looking at an example later on.
If successful the user is given access to the resource otherwise the flow is passed to the error page. In this case it forwards the user to the error page `error.do`.
You can develop your own implementation of the HttpAuthenticationMechanism interface if the three built-in implementations are not sufficient.
It must be implemented as a CDI bean with @ApplicationScope to ensure that it is available for instantiation by the container.
There are three methods defined by the interface
The validateRequest()method authenticates an HTTP request from a caller and is the only method that must be implemented.
The secureResponse() method secures the HTTP response message
And the cleanSubject() method
clears the subject of provided principals and credentials
All methods accept the same parameter types, which are: HttpServletRequest, HttpServletResponse, and HttpMessageContext.
These instances contain information about the caller and related security information as well as security related functionality.
Let’s have a look at an example implementation.
In this code example here you can see a simple implementation of the HttpAuthenticationMechanism interface.
See how the validateRequest() method is used to validate the user by invoking the `validate()` method on the injected `IdentityStoreHandler` and returns a `CredentialValidationResult`
It then uses the convenience method notifyContainerAboutLogin to notify the container bout the login successor failure.
Let’s dive a little deeper.
During an HTTP request, methods on HttpAuthenticationMechanism implementations are called at fixed moments during a request
This diagram shows when each method is called in relation to methods on a Filter and HttpServlet instances.
The validateRequest() method is invoked before the doFilter() or service() methods and in response to calling the authenticate() method on the HttpServletResponse instance. The purpose of this method is to permit a caller to be authenticated.
The secureResponse() method is called after the doFilter() or service() methods and provides post processing functionality on a response generated by a servlet or filter. A potential use case for this method is encryption.
Let’s take a quick look at the rememberme feature.
At the class level the optional RememberMe annotation can be used to effectively "remember" the authentication of the user, so it can be automatically applied with every request as demonstrated here.
@RememberMe
It has eight configuration options, all of which have sensible defaults, so you normally won’t need to specify a configuration value.
Here is a list of all methods available.
* `cookieMaxAgeSeconds`: Life of the remember me cookie
* `cookieMaxAgeSecondsExpression`: EL version of `cookieMaxAgeSeconds`
* `cookieSecureOnly`: The cookie should only be accessed via secure means (HTTPS)
* `cookieSecureOnlyExpression`: EL version of `cookieSecureOnly`
* `cookieHttpOnly`: Indicates that the cookie should be sent with HTTP requests only
* `cookieHttpOnlyExpression`: EL version `cookieHttpOnly`
* `cookieName`: The cookie’s name
* `isRememberMe`: Switches “remember me” on or off
* `isRememberMeExpression`: EL version of `isRememberMe`
Now let’s take a look at the Identity Store abstraction.
The new IdentityStore abstraction is used to interact with identity stores in order to authenticate users and retrieve group memberships.
It is intended that implementations of the IdentityStore interface are used by HttpAuthenticationMechanism implementations, although it isn’t a requirement.
In fact, `IdentityStore` implementations can be used by any other authentication mechanism the application developer wishes. The two concepts are not tied but are designed to work well together.
Containers are not tied to the `IdentityStore` either, but as most use case scenarios can be satisfied by their combined use it is recommended to use them together. By combining their use you enable an application to control the identity stores it uses for authentication in a portable and standard way.
Instances of the IdentityStore are handled via the IdentityStoreHandler which provides mechanisms for querying all available identity stores.
An instance of the IdentityStoreHandler is made available for injection as a CDI bean, as shown here, and used wherever authentication needs to happen.
@Inject
private IdentityStoreHandler idStoreHandler;
The IdentityStoreHandler interface has one method validate() which accepts a Credential instance.
Implementations of this method will typically invoke the validate() and getCallerGroups() methods of one or more IdentityStore implementations and return an aggregated result.
You can create your own lightweight identity store by implementing the IdentityStore interface, I will return to this later on in the presentation.
The security API comes with a default implementation of the IdentityStoreHandler interface which should suffice in most cases, however developers are free to replace it with their own implementation, if they are so inclined.
The default implementation authenticates against multiple IdentityStore’s. It iterates over a list of stores, and returns an aggregate result in the form of a CredentialValidationResult instance.
The security API comes with two built-in IdentityStore implementations for LDAP and rational databases. You provoke them with the appropriately named annotations.
The simplest built-in identity store is the database store and is configured via the @DataBaseIdentityStoreDefinition annotation as shown here.
@DatabaseIdentityStoreDefinition
The configuration options are fairly self-explanatory and should be familiar to you if you have configured a database definition and consist of 9 possible parameters which you can review in the Javadoc
However, note the priority that is set to 10, this is used when multiple identity stores have been implemented and determines their iteration order. I discuss the treatment of multiple IdentityStore’s implementations later on.
The LDAP IdentityStore bean is configured with the @LdapIdentityStoreDefinition annotation and is passed the configuration details required to connect to an external LDAP server.
@LdapIdentityStoreDefinition(
The LDAP configuration has far more configuration options than database configurations. If you have experience with LDAP configurations you will find the options familiar. The code snippet here shows a subset of those options.
Configurations are fairly self-explanatory and consist of 24 possible parameters which you can see in the Javadoc
Also notice a priority can be set here as well
Let’s look a little deeper at the identity store interface.
If the built-in identity stores don't satisfy your requirements, than a bespoke solution is possible by implementing the IdentityStore interface.
It has four methods, all of which have default implementations.
The validate() method validates a callers Credentials
and the getCallerGroups() method gets a caller’s group information
Either or both methods can be implemented and the methods that are actually implemented are notified by the validationTypes() method.
This feature allows the implementer flexibility to specify one identity store to perform authentication while letting another perform authorisation.
The vaidateTypes() method returns a Set of ValidationTypes that can be either VALIDATE or PROVIDE_GROUPS or both and indicate that the validate() method or the getCallerGroups() method or both methods are implemented, respectively.
and finally priority() method identifies the priority order in which the identity store should be executed.
As all methods in the `IdentityStore` interface are marked default, it is not necessary to provide implementations. By default both `validate()` and `getCallerGroups()` methods are called.
Multiple IdentityStore implementations are handled by the IdentityStoreHandler. The idea here is to allow multiple identity stores to effectively operate as one single IdentityStore.
The logic is quite involved and I won’t go in to too much detail as there really isn’t time, but essentially what it does is to call the validate() method of the identity stores in accordance with the capabilities declared by the validationTypes() method and in the order determined by the getPriority() method.
Let's look at a multiple identity scenario, to explain a little about what happens.
The identity store handler provokes a two phase iteration of the identity stores. The first phase look to validate the user credentials and the second iteration obtains the user’s group membership.
Imagine there are three identity stores. Identity store 1 connects to a database and identity stores 2 and 3 connect to an LDAP. In the diagram the identity store handler iterates over the IdentityStore instances in priority order, calling the validate() method on each instance until it finds a CredentialValidationResult that returns a VALID status. In this diagram, this happens on interrogating identity store 2. The handler stops the iteration and starts the second iteration to collect the caller’s groups.
This diagram represents the second iteration. This only happens if the first phase returned valid user credentials.
The identity store handler calls the getCallerGroups() method on each IndentityStore instance that declares that it’s validation type is PROVIDE_GROUPS. Which in this scenario it’s the identity store 3. The caller groups returned are combined with the set of group names returned by calling getCallerGroups() on the CredentialValidationResult instance returned by Identity Store 2.
Once all IdentityStore’s have been interrogated a CredentialValidationResult is constructed with a VALID status and the list of caller groups is returned.
This simple example demonstrates how it is possible for a caller to be validated by one IdentityStore and for a group membership list to be built from another.
The aim of the Security Context API is to provide a consistent approach to an application security across the servlet and EJB containers.
The security context provides access to security-related information associated with the currently authenticated user and can programmatically trigger the start of a web based authentication process in a consistent way across the servlet and EJB containers
The SecurityContext interface provides an entry point for programmatic security and is an injectable type. It consists of five methods.
Three methods allow the testing of caller data.
They are
The getCallerPrincipal() method. This method obtains the container-specific principal representing the name of the currently authenticated user. It will return null if the current caller is not authenticated.
The getPrincipalsByType() method. This method returns all Principals of the specified type from the authenticated caller's Subject
The isCallerInRole() method determines if the caller is included in the role passed in as a String. It returns true if the user has the role otherwise it returns false.
The last two methods are
The hasAccessToWebResource() method which determines whether or not the caller has access to the given web resource for the given HTTP method in the current application.
The authenticate() method programmatically triggers the container to start or continue an HTTP-based authentication conversation with the caller as if the client has made the call to access the resource.
This method is depends on a valid servlet context as it requires an HttpServletRequest and HttpServletResponse instance and therefore only works in the servlet container.
Now that we know the methods and how they function let’s take a look at some code examples.
The SecrityContext is made available by the container for inject via CDI and can be injected into any context aware instance.
In the first example the security context is used to test the logical roles in which the currently authenticated user participates. The roles being tested are admin, user and demo.
The second examples shows how to use the getCallerPrincipal() method to retrieve the platform-specific principle that represents the name of the authenticated caller. This method returns null if the current user is not authenticated so the appropriate null check needs to be done.
The final example shows how to use the getPrincipalsByType() method to retrieve a set of principles by type. In this case it retrieves that are of the CustomPrincipal type.
Here is another example that shows how to use the hasAccessToWebResource() method to test a caller’s access to a given web resource for a specified HTTP method. I have injected the SecurityContext instance into the servlet and called the hasAccessToWebResource().
Here I want to test if the caller has GET access to the resource locate at the URI /secretServlet so I pass these arguments to the method.
In this code example the authenticate() method is used to validate user-entered credentials.
The visitor enters a username and password into the JSF form below and when submitted the `LoginBean` processes and authenticates the credentials.
Now let’s move on to the new JSON binding API
The Java API for JSON Binding (JSON-B) 1.0 strengthens the Java EE platform’s overall support for the JSON data interchange format. Already, the Java API for JSON Processing (JSON-P) 1.1 has proved popular and together they form the perfect partners that fill a long standing shortcoming in Java EE’s JSON capacity.
The JSON-B specification codifies industry practices and methodologies that have become commonplace. It makes heavy use of annotations to mark classes and fields with mapping semantics, and provides the extensibility that is so often needed when dealing with complex data structures.
Out of the box, it provides default mappings for serialisation and deserialisation that meet reasonable expectations.
The default customisations are overridable with two customisation methodologies:
1. compile time annotations and
2. a runtime configuration builder.
For advanced customisations the API provides adapters and serializers/deserializers for times when the runtime builder and mapping annotations are not sufficient.
The primary feature of this API is the provision of binding support between Java classes and JSON documents in an intuitive and easy to use manner, such that a developer, with no prior knowledge of JSON, should be able to develop effectively with the API. For those with prior experience of other JSON de/serialization libraries such as GSON and Jackson, it will feel very familiar.
The JSON-B API provides two entry point interfaces: `Jsonb` and `JsonbBuilder`. The `Jsonb` interface provides the serialisation and deserialisation functionality via the methods `toJson()` and `fromJson()`, and the `JsonbBuilder` interface provides the client an access point to a `Jsonb` instances. It builds the instance based on a set of optional configurations.
Let’s jump in with a simple example that does a round-trip conversion of an instance of the `Book.class`.
To start a serialization or deserialization you need an instance of `Jsonb`. You create this by calling the static factory method `create()` on the `JsonBuilder` interface. With this instance you can perform all the serialisation and deserialisation operations you require by selecting the appropriate overloaded `toJson()` or `fromJson()` method.
In this code snippet, I call the simplest `toJson()` method and passed it a `book` object.
...
The return value of this method is a `String` that is the JSON data representation of the object passed to the `toJson()` method.
Now let’s turn our attention to the deserialization operation. It is just as simple as serialisation and also requires an instance of `Jsonb`. In the code snippet, I call the simplest `fromJson()` method and pass it the JSON `String` generated by the previous example, this is the JSON data I want to deserialize, and it’s target type as a `class` type.
...
In these examples, I have used the simplest `toJson()` and `fromJson()` method’s from the range of overloaded method available on the `Jsonb` interface. Now let’s dive a little deeper and look at how to customise the serialization and deserialization process..
For simple scenarios, the default mapping behaviour should be sufficient. However, for more complex scenarios there are several ways to customise its behaviour for your specific needs. I will introduce them later on in the presentation.
So, there a two customisation models that are used together or separately:
1. the annotation model and
2. the runtime model.
The annotation model uses built-in annotations to mark the field where the behaviour should be customised, and the runtime model builds a configuration strategy which is set on the `Jsonb` instance.
There are circumstances when annotations or the `JsonbConfig` builder cannot help.
For example, it's often not possible to annotate third party classes and classes that don't have a default constructor can be troublesome. There are two ways to deal with these situations; adapters and custom serializers/deserializers.
Let's take a look at how the annotation model and runtime configuration work.
Using the annotation method, it’s possible to customize the default serialization and deserialization behaviour by annotating fields, JavaBean methods, and classes.
For example, you could use the JsonbNillable annotation to customize null handling and the JsonbPropertyOrder annotation to customise the property order. These two annotations are specified at the class level.
You could specify the number format with the JsonbNumberFormat annotation and change the name of a field with the JsonbProperty annotation.
...
Alternatively, you could choose to handle customization with the runtime configuration builder, by configuration an instance of JsonbConfig and passing it to the create method of the Jsonb builder, as shown in this code snippet.
...
Either way, the JSON Binding API provides extensive capabilities for the serialization and deserialization of Java objects.
Let’s move on a look at how JSON-B handles custom object creation.
JSON-B expects all classes to have a public no argument constructor, which it uses during deserialization to instantiate the target class.
Once the instance is created, it is populated with data from the JSON document by calling the appropriate setter method or by directly setting the public field.
However, sometime this is not sufficient, especially when construction is complex, and for these cases, a custom constructor or static factory method must be implemented. The code here shows an implementation of a custom constructor.
...
You will notice the use of the `JsonbProperty` annotation to map JSON property names to the parameters in the constructor parameter list and how the constructure uses the firstname and lastname to construct an instance of the Author class.
This JSON document is successfully deserialized to the `Magazine` class.
{
"firstName": "Alex",
"surname": "Theedom",
"bookTitle": "Fun with JSON-B"
}
For a more sophisticated customisation of the serialisation and deserialisation process we need to take a look at how adapters function and that’s what I will do next.
An adapter configures custom object creation and serialisation by implementing the `JsonbAdapter` interface. The methods `adaptToJson()` and `adaptFromJson()` are overwritten with logic that performs the serialisation and deserialisation operation.
In the example implementation here, the `adaptToJson()` method has been implemented with code that transforms the `Booklet` object into a `JsonObject` using the JSON object builder from the JSON Processing API. The `adaptFromJson()` method constructs a `Booklet` object from a `JsonObject` instance.
...
As you can see, the `adaptToJson()` method ‘flattens’ the `Author` object to two properties: `firstName` and `lastName`.
The `adaptFromJson()` method reconstructs the `Author` object and outputs a `Booklet` instance.
The `JsonbAdapter` is very flexible and can be used to customise the serialisation and deserialisation of individual fields, as well as entire objects.
This is achieved by marking the field, method or class that should be customised with the `JsonbTypeAdapter` annotation and passing it the class name of the `JsonbAdapter` to use.
A example implementation is shown here. The `firstName` field is marked with the `JsonbTypeAdapter` annotation and the `FirstNameAdapter` class specified as the adapter.
...
And finally the most advanced way to customise JSON-B is with custom serializers and deserializers.
JSON-B serializers and deserializers are the lowest level of customisation available and give access to the JSON Processing parsers and generators.
A custom serializer must implement the `JsonbSerializer` interface and provide logic for the `serialise()` method. This code shows a simple example of how to customise the serialisation of the a `Book` object.
The `JsonGenerator` is used to create a JSON document property by property. The value of the `id` property is fixed and the author’s name is flattered to the `firstName` and `lastName` property.
....
The deserialization operation is customised by implementing the `JsonbDeserializer` interface and providing logic for the `deserialize()` method.
This code shows an example which extracts just the Book’s `id` from the JSON document.
….
Instances of the serializer and deserializer are registered with a `JsonbConfig` via the appropriate `withDeserializers()` or `withSerializers()` method as shown here.
...
Alternatively, the type can be annotated with `@JsonbTypeSerializer` or `@JsonbTypeDeserializer` and passed the class name of the relevant customisation class.
So we have seen today some exciting new changes in the way Java EE processes JSON.
JSON Processing is now up to date with the latest internet standards and the JSON-B’s designers have set out to standardize the way developers transform Java objects to JSON documents and vice versa.
If the API and features you’ve seen so far seem familiar to you, that is intentional: the API standardizes serialization and deserialization techniques that should be already familiar to most Java developers.
The two customisation models: runtime and compile time offer a highly flexible and intuitive way to fine tune the API.
The self-describing annotations and configuration methods contribute towards productivity and ease development.
Even so, lower-level manipulation of the serialization and deserialization operations and advanced customisation are easily achieved.