API-Led Connectivity with Mule

Introduction

Today, in the age of APIs an API is not just a technical interface on top of a database. On the contrary your API is your new Business Model. In the past APIs were seen as some tools for Developers. But now a days their scope is not only limited to internal use, the API makers (companies) are exposing their APIs for external users around the globe. For example Google maps APIs use the Uber APIs to calculate fare and travel time to destination.

In this API-Led business model it’s a new way of thinking how to engage with partners and customers through APIs. In other words your product is the API. So one must take proper care while designing based on business crietria, deploying and managing the APIs.

In this article, I am going going to discuss about the paradigm API-Led connectivity which has gained a lot of popularity in this decade.

The Digital Transformation

Now a days everywhere is happening the digital transformation with the involvement of Mobile and Cloud technologies. APIs once seen as developers’ tools are now being exposed to market. For example, through the Product Advertising API , Amazon sells its product through third parties.

However digital transformation is not an easy task. It involves the ability of the organisations to bring in multiple technolgies to create distinctive and disruptive services to the market. To happen this they must be able to retrieve data/information from disparate sources and provide them to multiple consumers (customers, suppliers and employees) in various formats.

Problems With Traditional Connectivity Approaches

The traditional approaches used for integration applications do not work for digital transformation. These approaches were designed where fewer endpoints were necessary to meet the business needs as well as the speed of delivery was not considered too much. Here are the problems faced with the traditional integration approaches,

P2P Approach

Image title

In P2P approach one business operation is connected to another operation by direct connection. In an organization where a lot of applications need to be integrated it becomes a mess with P2P approach. Here are the three main drawbacks of this approach,

  • Hard to change
  • Maintanability
  • High operation risk
  • Time to market

E2E

Image title

This approach focusses on centralizing information as much as possible. In this approach an integration platform is used (ESB) which serves as the base for collecting all the information and serving them to the final receiver. It  centralizes and reuses components e.g logging, error handling, transaction etc. This approach is much more efficient than P2P approach. However to meet the digital transformation of today’s age it is till not efficient enough because “Time to market” is till bigger with this approach.

So, to overcome these problems the new approach API-Led Connectivity is born.

API-Led Connectivity

This approach is based on Pace layers.The main purpose of API-led connectivity is to enable the integration flows to be reused by many parties and to be reused inside the integration platform. With the reusability of the already available logic (implemented in flows) the developers can evolve their logic in a faster and safer ways and thus leading to high uptime to the market. APIs are created in layers and the best plus point as comapred to E2E approach is that more components (flows) can be reused which makes easier to implement new systems and services.

As per research it shows that API-led connectivity approach makes the development process 3 tmes faster as one does not need to reinvent the wheel and thus decreasing the uptime to market. As the reusable APIs are already tested use of them makes the new implementations bug free. The reduced development time reduces the integration costs by around 70% (as per the statistics).

In this approach the APIs are based in three distinct layers: System, Process and Experience. With API-Led architecture the IT infrastructure of an organization should look more or less as shown in the diagram below.

Image title

System Layer

This is the foundational layer of the three layer architecture. These APIs can be defined for various domains of an organisation for example ERP, key customer and billing systems, proprietary databases etc. System APIs provide a means of accessing these underlying systems of records and exposing the data in canonical formats. A System API defines the contract RAML/WSDL to describe how to interact with the the domain. For example, a System API for Customer domain can contain resources with methods GET,POST,PUT,DELETE etc and the related schemas (XSD,JSON) and responses (200,400,500 etc).

Image title

So basically one can see that System APIs generally expose the sensitive informations of an organization. They should not be exposed for public use.

Process Layer

Process layer APIs are responsible for shaping the data by orchestrating and choreographing various data by calling multiple System APIs. The orchestration involves aggregating, splitting , routing etc of data. The main purpose of Process APIs is to strictly encapsulate the Business Process independent of the source systems (System APIs) from which data originates.

For example, in a Purchase Order process it needs to interact with various domains of the organization. So the Process API (Purchase Order/Order Fulfillment) interacts with the already available System APIs to implement the logic.

The Process APIs shoud be held privately inside the organization as per recommendation and should not be exposed for public use.

Image title

Experience Layer

Now at this point we have all the sensitive information of an organization are exposed privately by System APIs and the Process APIs have already exposed the Business Process logic. The business process data is consumed across a broad range of clients/channels with different formats. For example our Order Purchase API (Process Layer) has exposed data in JSON format but we have a client appliction that accepts only in XML format or vice versa. So this simple transformation logic are implemented in Experience Layer and the implementations are exposed as Experience APIs.

In another words Experience APIs are the means by which data can be reconfigured easily to meet the needs of multiple audiences. Also we can remove the unnecessary methods and expose only the necessary methods in Experience APIs in a simple way.

The Experience APIs are the ones which should be exposed publicly for consumption. In short they are the final products of an organization in the API-Led connectivity approach. Various Policies can be applied to the APIs as well as they can be monetized to earn revenue for the organization.

Image title

Main Advantages of Three Layer APIs

The main benifits of the three layer can be summerised as below.

System APIs

One can modify the System API logic without affecting the other APIs (Process and Experience). For example if a System API is using SAP and in future SAP needs to be replaced with Salesforce. So this replacement can be done easily modifying only the System API without touching anything in Process and Experience layer.

Process APIs

Common business logic can be shared across the organization. For example if an organization already has the Purchase Order process API implemented it can be reused whenever necesary.

Experience APIs

Experience APIs are simple. Basically they involve only transformation of data. So to meet a wide range of clients that accept data in diverse formats the Experience APIs do this rapidly thus decreasing the uptime to market.

Role of Mulesoft in API-Led Connectivity

The Anypoint Platform provides a very nice Integration Framework as well as an API Management platfrom. Using the Anypoint Platform as a whole one can achieve the API-Led connectivity in a smoother way.

Conclusion

In this article I have given a brief overview of the API-Led connectivity. In the next article I will try to show how to achieve this with some examples using Anypoint Platform.

Thanks.

 

Reference links:

https://www.mulesoft.com/lp/whitepaper/api/api-led-connectivity

 

Why Domain Project ?

Introduction

Mule has the concept of Domain Project to share common resources. But as per the documentation there are some limitations of using Domain Project to share resources. Here are the main limitations as per the documentation,

  • Defining flows, subflows, or any message processors as shared resources is not supported.
  • To share a WMQ connector as a shared resource, you need to remove the mule-transport-wmq-ee-.jar file from the $MULE_HOME/lib/mule/per-app/ directory and remove all the native jars for WMQ connectivity in your application’s $MULE_HOME/apps//lib/ directory. Place all these jars in the $MULE_HOME/domains//lib/ folder instead.
  • Adding properties in the configuration files of applications that use shared resources can result in issues, as these properties are shared with other apps in the domain and there may be conflicts. You can instead set environment variables.
  • Only the following connectors and related specifications can be specified as shared resources at this time:
    • HTTP/HTTPS (both endpoints and connectors)
    • VM
    • TLS Context elements
    • JMS
    • JMS Caching Connection Factory
    • Database
    • WMQ
    • JBoss Transaction Manager
    • Bitronix Transaction Manager

But why to use Domain Project ?

I am not totally sure what is the main purpose of this Domain Project concept if we can NOT share some important common flows. For example, suppose we have some exception strategy flows which are common among various projects. So as per the documentation Domain Project will not serve our purpose.

My Argument

On the other hand , Mule has this out of the box concept where every flow is treated as spring bean.

So my argument is why should not we create a project and put all the common flows, resources (HTTP,VM etc connections ) and export it as jar and use it as dependency in other projects and load the flows as spring bean.

Experiment

In this experiment , first I will create a project with shared resources. For simplicity I am creating the following shared resources.

  1. One HTTP listener.
  2. Common exception handling strategy.

And most importantly I am exporting this project as jar file instead of conventional zip . Here is the source code of the project. In this project, I have two flows only.

connections.xml

screen-shot-2017-01-03-at-5-16-22-pm
connections etc.

This is an empty flow without any flow elements. It only contains a HTTP Listener configuration.

my-common-flows.xml

This configuration file contains a single flow called  common-exception-handling.

common-flow
Common Exception Flow.

init-DEV.properties

Also I have a simple property file with a simple property as shown below.

init-dev-properties
init-DEV.properties

pom.xml

Most importantly I am not using the zip packaging format in the pom.xml file. Instead I am packaging it as jar. Please check this part of the pom.xml file as shown below,

pom
pom.xml

Using the common resources

Now we are going to use this common resource in a project. The source code is available here. So, first of all we will modify the pom.xml file of the project and insert dependency of the common resource project we have created above. Here is a part of the pom.xml,

maven-dependency
use shared resources.

And that’s it. Now we can use the shared resources. Here in this project we have a simple flow where I am using the following shared resources,

  1. HTTP Listener (declared in connections.xml of the common project).
  2. Common exception handling (declared in my-common-flows.xml of the common project)
  3. A shared property (declared in the init-DEV.properties of the common project).

Here is the simple flow diagram,

use-shared-resources
Use shared resources.

The most important part in the configuration file my-domain-test.xml is the following,

spring-import
Spring Bean Import

Conclusion

The example shown above eliminates the use of Domain Project. Whatever we can share in a Domain Project we can achieve the same thing using a common project or we can achieve even more (sharing common flows).

So, what exactly is the purpose of a Domain Project ? I would appreciate your opinions.

Thanks.

Troubleshoot

On importing the shared resources in other projects , sometimes Anypoint studio fails to load the resources. To solve it, just close and open the project.

Credential Vault

Introduction

When we define properties in .properties file in a project a lot of properties contain sensitive information for example Jdbc password etc. So the best way is to protect this information by encrypting it.

Mule provides its out of the box functionality called Credentials Vault to encrypt the individual properties in the .properties file. The dictionary meaning of Vault is “an arched structure of masonry usually forming a ceiling or roof”. So, in our case once the .properties file becomes encrypted it becomes the Vault.

Let’s start

First of all you need to have the Mule Security Modules installed in your Anypoint Studio. Do please read the installation part of Mule Security Module in this post. After installing the security modules the rest is very simple.

Project configuration

Do please find the source code of the project in the following link. In the project I have created a very simple flow called vault-example.xml. In the resource folder I have created a file called init.properties. Please right click on it and open with Mule Properties Editor as shown in the diagram below.

structure
Structure

Step 1

Now let’s create some properties. After opening the init.properties  file with Mule Properties Editor now please click the green button and add property (key & value) as shown below,

add-property
Add property.

Step 2

Now click the button Encrypt. A pop-up screen will be shown and you will be asked to choose Algorithm and Key for encryption. For simplicity I have chosen Blowfish as algorithm and “mule” as key. Please refer to the diagram,

encrypt
Encrypt

Step 3

You should see the screen after Step 2. You can click the button Encrypt/Decrypt to see the value (encrypted/decrypted) as shown below.

flip
Encrypt/Decrypt

You can add some more properties.

Step 4

Now the encrypted init.properties is our vault and we will use this vault in our flow vault-example.xml. So please open the Global Elements tab and let’s add a Property Placeholder element to refer to our init.properties file.

property-plaeholder
Property Placeholder.

And then in the Location field, point to the init.properties file.

location
Add location of our properties file.

Step 5

After that we have to add a global element called Secure Property Placeholder. It will contain the necessary information of our key that was used to encrypt/decrypt our properties. The key we used was mule. Here is a screenshot,

spp
Hardcode key

I am using the key hard coded. A better way is to put it in the mule-app.properties. I have put a property in this file and named it as

vault.key=mule

Now, please see the updated Secure Property Placeholder configuration. Check it out below,

spp1
Variable key

Testing

Now, in the flow , just put a logger and let’s check if we can have decrypted output of an encrypted property in our init.properties file. Here is a screenshot,

testing
Testing.

Note

Probably at this point when you run the application you are not able to see the decrypted output in the Anypoint Studio console. I don’t know why. The trick is that when context property placeholder configuration precedes the secure property placeholder configuration  it does not work. The work around is to put the it  after.

Just take a look at the .xml configuration file,

mule-config
Trick

So, that’s it. Now when you run the application and make a request to the end point http://localhost:8081/vault you will see the decrypted value in the console.

HTTPS-Mule

Introduction

Mule provides out of the box supports for HTTPS. Here in this post I am going to explain how to create a simple HTTPS server and access it.

Before we begin

Before we begin, let’s understand a little bit about Keystore and Truststore.

Keystore: In short Keystore is a server side asset which stores the private keys and the certificates with their public/private keys.

Truststore: Truststore is a client side asset which serves as a repository of certificates (CA or simple) that the client should trust.

To know more about Keystore and Truststore please read this article.

Creating Keystore and Truststore

Let’s get our hands dirty now. The process is as follows,

  1. Create the Keystore and generate a certificate.
  2. Export the certificate.
  3. Import the certificate to the Truststore.

step 1

We will use the keytool that comes with Java. Please create a temporary directory somewhere in your drive.Now please open a terminal and navigate to the directory and execute the following command,

keytool -genkey -alias mule -keyalg RSA -keystore keystore.jks

On execution, it will ask keystore password and some general information. And at the end it will ask for the password of the key.Points to be noted ,

key: mule

keystore:  keystore.jks

keystore password:  keystorepass

key password: keystorepass

(Please feel free to use different passwords for keystore and key. I used the same password for the sake of simplicity). Here is a simple screenshot,

keystore
Create Keystore.

Step 2

The process above creates a keystore as well as a certificate. Now we have to export the certificate so that it can be added to the truststore as the trusted certificate. Now please execute the following command in the terminal,

keytool -export -alias mule -file client.cer -keystore keystore.jks

The key points here is to specify the key (mule) and the keystore (keystore.jks) we have created in the previous step. You can use any file name. Here I am calling it as client.cer. On executing it will ask for the password of the keystore.In our case it is keystorepass. Here is a screenshot,

certi
Create certificate.

Step 3

After creation of the certificate (client.cer) we will populate our truststore with it. So, let’s create a truststore. Please execute the following command in the terminal,

keytool -import -v -trustcacerts -alias mule -file client.cer -keystore truststore.ts

Important points to be noted here is the key (in our case it’s mule) , the certificate file (client.cer) and the name of the truststore (truststore.ts). On execution of the command, it will ask for password for the truststore being created. You can choose anything you want. I have chosen truststorepass for simplicity. Here is a screenshot,

truststore
Generate Truststore.

Okay, you are done with creation of Keystore and Truststore. Congrats. Now let’s move on to next steps.

Create a simple Mule project.

Let’s create the simplest mule project and the simplest flow. The scenario is as follows, “We have a HTTP server running on port 8081. On sending request to the server on the http://localhost:8081/app/ uri, it will call an HTTPS server running on port 8082″. That’s it. Here is a screenshot,

flow
Flow

HTTPS Server Configuration

I have copied the keystore and truststore to the resource/keystore directory of the project. Please check the screenshot,

project-structure
Project Structure.

Now let’s configure the flow HTTPS_Server_OneWaySSL. Here is the screenshot,

https
HTTPS

Do remember that in the Server we are using the keystore.

HTTPS Client Configuration

Now let’s configure the flow HTTPS_Client_OneWaySSL. 

http_client_general
HTTP Client configuration (General)
http_client_ssl
Http Client Configuration (SSL)

 

Remember that here in the client configuration we are using the truststore created.

Now execute the flow and make a request in the uri http://localhost:8081/app/. You should get a response from the HTTPS server running on 8082.

 

That’s it. Please find the source code here.

 

 

Mule Message Encryption-XML Encrypter

Introduction

In the post I have explained how to configure Anypoint Enterprise Security module and also shown how to use the JCE Encrypter. Please read the whole post before stepping into this post. It’s very important.

Objectives

The main objective of this post is to use the same flow we have used in the post. The flow is as follows. “We send some XML data to an HTTP endpoint. Then the XML data is encrypted using XML Encryption Strategy and we log the encrypted data. After that we simply decrypt the encrypted data and log it”. Here is diagram of the flow,

flow
Flow Diagram

Step 1

Now configure a global Encryption Element named as XML_Encrypter 

global-element
Global Element configuration.

Step 2

In the flow configure the Encrypt component,

encrypt-elm
Encrypt Element General Config.

In the Connector Configuration please select the global encryption element(XML_Encrypter) that we have defined in step 1. In the Operation dropdown select Encrypt. In the Input Reference field please put the payload. Now  select the encryption strategy as XML_ENCRYPTER. As we are using XML_ENCRYPTER in this example, let us configure it. Select the Define attributes radio button in the XML encrypter Strategy Configuration for operation category.

encrypt-element-xml-strategy-config
XML Strategy config.

Here we are encrypting only the name xml element using  Xpath.

Step 3

In the step 2 we have encrypted the message. Now let’s decrypt the encrypted message. Here we are going to configure the component labelled as Decrypt payload. 

decrypt-config
Decrypt General Config.
sasa
Decrypt XML Config.

The configuration is almost same as for encryption. The only difference is the

Operation: Decrypt

Testing

Now let us run the project. After running the project, send a POST request with XML payload. I am using Postman for this operation. On observing in the Anypoint console you can see the encrypted message as well as decrypted message.

test
Test Data

Sample result

INFO  2016-12-11 23:27:49,150 [[springbeanexample].HTTP_8081.worker.01] org.mule.api.processor.LoggerMessageProcessor: <?xml version="1.0" encoding="UTF-8"?><book>
	<name><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Content"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#kw-aes128"/><xenc:CipherData><xenc:CipherValue>w6kq/2uvqK/EX+Z9ROWKMCW+wRwLdehj</xenc:CipherValue></xenc:CipherData></xenc:EncryptedKey></ds:KeyInfo><xenc:CipherData><xenc:CipherValue>DIO/ZC/PrlpdBVnl2uzUTPDuGhXuO1tXF54qH0k70cE=</xenc:CipherValue></xenc:CipherData></xenc:EncryptedData></name>
	<author>Anupam</author>
</book>
INFO  2016-12-11 23:27:49,159 [[springbeanexample].HTTP_8081.worker.01] org.mule.api.processor.LoggerMessageProcessor: <?xml version="1.0" encoding="UTF-8"?><book>
	<name>ABC</name>
	<author>Anupam</author>
</book>

Please find the source code here.

N.B: Use mvn eclipse:eclipse to import the maven dependencies.

Mule Message Encryption-JCE Keystore

Introduction

This is the second part of my previous post. In the previous post in the JCE Encrypter configuration I did not use Keystore. Here in this post I will create a Keystore and use it for encryption.

Let’s get dirty

First we will create a Keystore using Keytool that comes with JDK. After that we will create a simple project and use the generated keystore for message encryption.

Create Keystore

JDK comes with its inbuilt tool Keytool to create keystores. First let’s create a keystore using the native Keytool.

Let’s create a temporary directory. I have created a temporary directory named as encryption as shown below,

screenshot-at-2016-12-10-20-45-42
Temporary directory

Now let’s execute the following command.

keytool -genseckey -keystore aes-ackeystore.jck -storetype jceks -storepass acstorepass -keyalg AES -keysize 128 -alias ackey -keypass ackeypass
 

After execution of the command a keystore aes-ackeystore.jck is generated in the directory.Basic things to point out in the command are as follows,

Name of the keystore : aes-ackeystore.jck

Password of the keystore: acstorepass

Name of the key: ackey

Password of the key :  ackeypass

These are the principal information that we need to configure our JCE Encryptor using keystore.

Create a simple Mule Project

Please strongly refer to the post for Anypoint Enterprise Security module installation.Let’s create a simple Mule Maven project using Anypoint Studio. The most important point is to add the following repository in the pom.xml file.

<repository>
   <id>mulesoft-public</id>
   <name>MuleSoft Public Repository</name>
   <url>https://repository.mulesoft.org/nexus/content/repositories/public/</url>
   <layout>default</layout>
</repository>

Please note that I have copied the generated keystore (in the previous step) to the resource folder of the project. Here is a screenshot of the project structure.

Folder Structure.png

Creating a simple flow

Let’s create a simple flow. The scenario is as follows. We send some JSON data to an HTTP endpoint. Then the JSON data is encrypted using JCE Encryption Strategy and we log the encrypted data. After that we simply decrypt the encrypted data and log it. Here is diagram of the flow.

flow_jce_keystore
Flow Diagram

Digging into JCE Encryption

“The Java Cryptography Extension (JCE) is an officially released Standard Extension to the Java Platform and part of Java Cryptography Architecture. JCEprovides a framework and implementation for encryption, key generation and key agreement, and Message Authentication Code (MAC) algorithms.”

Step 1

First let’s configure a global Encryption element.

global-element
Global Encryption Element configuration.

Do mind it to select the Default Encryptor dropdown as JCE_ENCRYPTER.  I have named the global element as JCE_Keystore.

Then select the JCE Encrypter tab and configure it as shown in the diagram,

jce-encrypter-config
JCE Encrypter Configuration

Step 2

Now after configuring the global Encryption element in step 1 let’s configure the Encryption component (labeled as Encrypt in the flow. This is a Encryption palette found under the Security category of Mule palettes). Here is the screen shot,

encryption-palette-config
Encryption Palette Configuration

In the Connector Configuration please select the global encryption element(JCE_Keystore) that we have defined in step 1. In the Operation dropdown select Encrypt. In the Input Reference field I am putting the whole payload (JSON data) for encryption. Do remember that you can use MEL expression here to encrypt some part of the payload too. And that’s it. No more configuration is needed and you are ready to go.

Step 3

In the step 2 we have encrypted the message. Now let’s decrypt the encrypted message. Here we are going to configure the component labelled as Decrypt. (It’s nothing but a Encryption  palette found under the Security category of Mule palettes. Here is the configuration,

decrypt-config
Decrypt Config.

The configuration is almost same as for encryption. The only difference is the

Operation: Decrypt

Testing

Now let us run the project. After running the project, send a POST request with JSON payload. I am using Postman for this operation. On observing in the Anypoint console you can see the encrypted message as well as decrypted message.

testting
Testing with Postman.

Sample log in Anypoint console,

INFO  2016-12-10 21:23:26,602 [[springbeanexample].HTTP_8081.worker.01] org.mule.api.processor.LoggerMessageProcessor: XjeegDtusFQSovOSxqZgr1j5oCUYypD4/7X6NjworIQ=
INFO  2016-12-10 21:23:26,613 [[springbeanexample].HTTP_8081.worker.01] org.mule.api.processor.LoggerMessageProcessor: {
	"name":"anupam"
}

Please find the source code here.

N.B: Use mvn eclipse:eclipse to import the maven dependencies.

Mule Encryption

Introduction

“Do not reinvent the wheel.” , that’s the principle Mule applies when it comes to Mule Message Security. Anypoint Enterprise Security is a suite that comes bundled with all the necessary modules/methods for applying security to Mule Service Oriented Architecture (SOA) implementations and Web services.

Objectives

My main concern regarding the security was Mule Message Encryption. Mule provides three extraordinary Encryption Strategies

  • JCE Encrypter: encrypts stream, byte[] or string.
  • XML Encrypter: encrypts string, encrypts individual fields using xpath expressions.
  • PGP Encrypter: encrypts stream, byte[] or string.

In this blog post I will try to explain how to configure Anypoint Studio for applying encryption strategies to mule messages using the JCE Encrypter.

Getting your hands dirty

Let’s get our hands dirty. I will try to explain everything starting from the installation of Anypoint Enterprise Security. Also I would like to point out the troubleshooting during the installation process.

Installation of Anypoint Enterprise Security

I am using Mule 3.8 EE for this experiment. Please do take a look at this link for the installation guide in detail. Here is a screenshot,

screen-shot-2016-12-09-at-4-38-55-pm

Please select the Premium bundle and proceed. In my case I could not install the software initially. If the same problem continues in your case please uncheck the “Contact all update sites during install to find required software” checkbox.

After successful installation restart your Anypoint studio. You should see the following components  under the security group palettes.

security_pallete
Security components

Now you are ready to go !

Create a Mule maven project

Let’s create a simple Mule Maven project using Anypoint Studio. The most important point is to add the following repository in the pom.xml file.

<repository>
   <id>mulesoft-public</id>
   <name>MuleSoft Public Repository</name>
   <url>https://repository.mulesoft.org/nexus/content/repositories/public/</url>
   <layout>default</layout>
</repository>

Creating a simple flow

Let’s create a simple flow. The scenario is as follows. We send some JSON data to an HTTP endpoint. Then the JSON data is encrypted using JCE Encryption Strategy and we log the encrypted data. After that we simply decrypt the encrypted data and log it. Here is diagram of the flow.

flow-diaram
Simple Flow Diagram

Digging into JCE Encryption

“The Java Cryptography Extension (JCE) is an officially released Standard Extension to the Java Platform and part of Java Cryptography Architecture. JCEprovides a framework and implementation for encryption, key generation and key agreement, and Message Authentication Code (MAC) algorithms.”

Step 1

First let’s configure a global Encryption element.

encryption_global_elm
Encryption Global Element Configuration

Do mind it to select the Default Encryptor dropdown as JCE_ENCRYPTER.  I have named the global element as JCE.

Step 2

Now after configuring the global Encryption element in step 1 let’s configure the Encryption component (labeled as JCE Encryption in the flow. This is a Encryption palette found under the Security category of Mule palettes). Here is the screen shot,

configure_encryption_in_flow
Configure Encryption component in the flow.

In the Connector Configuration please select the global encryption element(JCE) that we have defined in step 1. In the Operation dropdown select Encrypt. In the Input Reference field I am putting the whole payload (JSON data) for encryption. Do remember that you can use MEL expression here to encrypt some part of the payload too. As we are using JCE_ENCRYPTER in this example, let us configure it. Select the Define attributes radio button in the JCE encrypter Strategy Configuration for operation category.

Key:  It must be a 16 digit phrase.

Key Password:  (whatever you wish)

Algorithm:  Choose an algorithm from the dropdown list.

Encryption Mode: Choose from the dropdown list.

That’s it. You are ready to go. There is another way to make it more secure  using Keystore. I will show you later in another post.

Step 3

In the step 2 we have encrypted the message. Now let’s decrypt the encrypted message. Here we are going to configure the component labelled as Decrypt payload. (It’s nothing but a Encryption  palette found under the Security category of Mule palettes. Here is the configuration,

Configuration for Decryption.

The configuration is almost same as for encryption. The only difference is the

Operation: Decrypt

Testing

Now let us run the project. After running the project, send a POST request with JSON payload. I am using Postman for this operation. On observing in the Anypoint console you can see the encrypted message as well as decrypted message.

postman
Testing with Postman.

Please find the source code here.

N.B: Use mvn eclipse:eclipse to import the maven dependencies.

Json View

Recently  I had a requirement. When exposing a service as REST and making data available at GET endpoint as JSON, I wanted to filter out some fields. For example, I have a User class with the following properties.

class User
{
   Integer userId;
   String firstName;
   String lastName;
   String email;
   String phone;
   Integer age;
   String homeAdress;
   String officeAddress;
}

Many times I don’t need the whole information of the User and instead of that I only want the [userId, firstName, lastName,email and phone] only. For that I could have used the @JsonIgnore annotation on those unnecessary properties. But if I do so, these properties will always  be ignored and I could never be able to get the full User information in case it becomes necessary.

Fortunately, JSON has a concept of Json View. And it’s really simple to implement. Here is the complete source code for it. Let me only show you what is the important point in the implementation.

Step 1

Let’s make a Profile class.

package com.anupam.app.profile;

import org.omg.CORBA.COMM_FAILURE;

/**
 * Created by brisatc186.gogoi on 10/11/2016.
 */
public class DataProfile
{

    /**
     * [id,firstName,lastName] of {@link com.anupam.app.controller.User}
     */
    public static class CommonInfo
    {
    }

    ;

    /**
     * [id,firstName,lastName,email,phone] of {@link com.anupam.app.controller.User}
     */
    public static class BriefInfo extends CommonInfo
    {
    }

    ;

    /**
     * [id,firstName,lastName,email,phone,age,homeAddress,officeAddress] of {@link com.anupam.app.controller.User}
     */
    public static class FullInfo extends CommonInfo
    {
    }

    ;
}

Step 2:

Let’s assign these profiles to the properties of the User.clss

class User
{
    @JsonView(DataProfile.CommonInfo.class)
    Integer userId;

    @JsonView(DataProfile.CommonInfo.class)
    String firstName;

    @JsonView(DataProfile.CommonInfo.class)
    String lastName;

    @JsonView({DataProfile.BriefInfo.class, DataProfile.FullInfo.class})
    String email;

    @JsonView({DataProfile.BriefInfo.class, DataProfile.FullInfo.class})
    String phone;

    @JsonView(DataProfile.FullInfo.class)
    Integer age;

    @JsonView(DataProfile.FullInfo.class)
    String homeAdress;

    @JsonView(DataProfile.FullInfo.class)
    String officeAddress;

    public String getPhone()
    {
        return phone;
    }

    public void setPhone(String phone)
    {
        this.phone = phone;
    }

    public Integer getUserId()
    {
        return userId;
    }

    public void setUserId(Integer userId)
    {
        this.userId = userId;
    }

    public String getFirstName()
    {
        return firstName;
    }

    public void setFirstName(String firstName)
    {
        this.firstName = firstName;
    }

    public String getLastName()
    {
        return lastName;
    }

    public void setLastName(String lastName)
    {
        this.lastName = lastName;
    }

    public Integer getAge()
    {
        return age;
    }

    public void setAge(Integer age)
    {
        this.age = age;
    }

    public String getHomeAdress()
    {
        return homeAdress;
    }

    public void setHomeAdress(String homeAdress)
    {
        this.homeAdress = homeAdress;
    }

    public String getOfficeAddress()
    {
        return officeAddress;
    }

    public void setOfficeAddress(String officeAddress)
    {
        this.officeAddress = officeAddress;
    }

    public String getEmail()
    {
        return email;
    }

    public void setEmail(String email)
    {
        this.email = email;
    }
}

Step 3:

Now lets create a simple controller and on each method let’s define the Profile we want.

package com.anupam.app.controller;

import com.anupam.app.profile.DataProfile;
import com.fasterxml.jackson.annotation.JsonView;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by brisatc186.gogoi on 10/11/2016.
 */

@RestController
@RequestMapping("/user")
public class UserController
{

    @GetMapping(path = "/full_info", produces = MediaType.APPLICATION_JSON_VALUE)
    @JsonView(DataProfile.FullInfo.class)
    public User getFullUserInfo()
    {
        User user = makeDummyData();
        return user;
    }

    @GetMapping(path = "/brief_info", produces = MediaType.APPLICATION_JSON_VALUE)
    @JsonView(DataProfile.BriefInfo.class)
    public User getBriefUserInfo()
    {
        User user = makeDummyData();
        return user;
    }

    public User makeDummyData()
    {
        User user = new User();
        user.setUserId(1);
        user.setFirstName("Json");
        user.setLastName("Bond");
        user.setEmail("json.bond@gmail.com");
        user.setPhone("11-34560987");
        user.setAge(37);
        user.setHomeAdress("LA");
        user.setOfficeAddress("CA");
        return user;
    }
}

That’s it. Now run the application and use the uris,

http://localhost:8080/user/brief_info

http://localhost:8080/user/full_info

STOMPing

Recently I was playing with the STOMP protocol. Spring framework provides a very nice integration with the STOMP protocol. STOMP simply means Simple Text Oriented Messaging Protocol. Whoever wants to look into the documentation of Spring+Stomp integration can follow this Spring+Stomp.

Here, my intention is not to explain the STOMP, but want to show how beautiful it is ! On the contrary of the traditional synchronous (request response)  messaging , it is completely asynchronous. For example the Stock applications. They give you the real time updates of the stock values.Another example can be a chat example.

How I played with STOMP ?

My aim was to make a simple message oriented architecture where various clients (Web browser, Java client) can communicate asynchronously. As I already told that Spring provides a nice integration with STOMP, I chose the Spring framework and set up a very simple (without exaggeration) Spring project. If you want to jump to the project directly then here is the git App.

I did use the spring configuration in Java as it is much more convenient than the traditional xml configuration. Here I would like to discuss only the salient points that I discovered while trying to understand the topic.

    • The Message Broker configuration class
package com.anupam.app.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.server.standard.TomcatRequestUpgradeStrategy;
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;

@Configuration
@EnableWebSocketMessageBroker
public class SpringStompConfig extends AbstractWebSocketMessageBrokerConfigurer {
	@Override
	public void configureMessageBroker(MessageBrokerRegistry config) {
		config.enableSimpleBroker("<span style="color: #ff9900;"><strong>/topic</strong></span>");
		config.setApplicationDestinationPrefixes("<span style="color: #4fad0c;"><strong>/app</strong></span>");
	}

	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		registry.addEndpoint("<strong>/websocket</strong>").withSockJS();
		registry.addEndpoint("/websocket")
			.setHandshakeHandler(new DefaultHandshakeHandler(new TomcatRequestUpgradeStrategy()))
				.setAllowedOrigins("*");
	}

}

Points to be noted:

  1.  In the second method,
registerStompEndpoints(StompEndpointRegistry registry)

I have declared the Endpoint as “/websocket“. It means that all STOMP request must be sent to this endpoint. After declaring the endpoint, I have added a special line of code, otherwise the Tomcat server complains to upgrade it to Websocket support.

      2. In the first method,

configureMessageBroker(MessageBrokerRegistry config)

I have declared a simple in-memory message broker with the the destination prefix “/topic“. It means we can subscribe to messages in the destinations for example “/topic/xyz” etc.

Then in the line below, I have added a prefix named as “/app” for the destinations (@MessageMapping) on which we will publish messages. Do please look at the message controller class StompController  .

        @MessageMapping("/ping")
	@SendTo("/topic/ping")
	public String ping(String message) throws Exception {
		System.out.println(message);
		return message;
	}

Look at the @MessageMapping annotation as shown above. So, to publish/send a message to the “/ping” destination, we must add the “/app” prefix to it. So, from client applications we will be publishing message on this destination “/app/ping“.

And to subscribe to message we have to listen on the topic “/topic/ping“. Please check the @SendTo annotation in the above piece of code. You can put any destination name but it must have a prefix “/topic“. It’s because we have defined

config.enableSimpleBroker("/topic");

in the message broker configuration.

    • The ServletInitializer

This ServletInitializer class is same as configuring servlet-mapping in the web.xml. As I am using Java config, I have to map the urls for our websocket message broker.

package com.anupam.app.config;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class ServletInitializer implements WebApplicationInitializer {

	public void onStartup(ServletContext container) throws ServletException {
		// Context
		AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
		ctx.register(SpringAppConfig.class, SpringStompConfig.class);

		// Manage the life cycle of the root application context
		container.addListener(new ContextLoaderListener(ctx));

		// Register and map the dispatcher servlet.
		ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(ctx));
		dispatcher.setLoadOnStartup(1);
		dispatcher.addMapping("/rest/*");
		dispatcher.addMapping("<strong>/ws/*</strong>");
	}

}

Here I have mapped the url pattern as “/ws/*” for all the STOMP requests. Please do not forget to do this.

      • Writing a simple web client-AngularJS

My intention was to write a browser client containing a simple textbox and a send button so that one can send message to backend. The back end replies with the same message sent and shows up in a small text area in the browser.

<html lang="en">

<head>
<!-- Bootstrap-->
	<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<!-- Angular JS -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
 <!-- Web Socket -->
 <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.1/sockjs.js"></script>
 <!-- App -->
 <script src="app/scripts/app.js"></script>
</head>

<body ng-app="stompapp" ng-controller="MyController">
<div class="panel panel-default" style="width: 400px">
<div class="panel-heading">STOMP Testing</div>
<div class="panel-body">
<textarea class="form-control" rows="10" ng-model="info.msgoutput"></textarea>


<input type="text" class="form-control" ng-model="info.msginput">


<button ng-click="onStomp()" class="btn btn-primary">Stomp</button>
</div>
</div>
</body>

</html>

Do please import the stomp.js and sockjs.js properly. And of course do not forget to include your own app.js. Here goes my app.js.

var app = angular.module('stompapp', []);
app.controller('MyController', function($scope) {
	var client = null;

	$scope.info = {
		msginput : &amp;amp;amp;amp;quot;&amp;amp;amp;amp;quot;,
		msgoutput : &amp;amp;amp;amp;quot;&amp;amp;amp;amp;quot;
	};

	// Connect to Websocket.
	connectStomp();

	function connectStomp() {
		var socket = new SockJS('/springjavaconfig/ws/websocket');
		client = Stomp.over(socket);
		client.connect({}, function(frame) {
			console.log('Connected: ' + frame);

			// Subscribe to messages published on this destination.
			client.subscribe('<span style="color: #ff9900;"><strong>/topic/ping</strong></span>', function(result) {
				var data = result.body;

				$scope.info.msgoutput = data;
				$scope.$apply();
			});
		});
	}
	;

	// Send a message.
	$scope.onStomp = function() {
		client.send('<span style="color: #339966;"><strong>/app/ping</strong></span>', {}, $scope.info.msginput);
	};

});

This is a very simple angularjs controller script. Please note the following things in the script.

  1. The websocket url.
var socket = new SockJS('/springjavaconfig/ws/websocket');

Do not forget the url mapping we added “/ws/*” in the ServletInitializer class and the websocket endpoint we have configured in SpringStompConfig  as “/websocket“.

      2. Subscription to a message destination

client.subscribe('/topic/ping', function(result) 
                        {
                             var data = result.body;
                             $scope.info.msgoutput = data;
			     $scope.$apply();
			}
                );

I have subscribed to the destination “/topic/ping“. If you look carefully in the message controller StompController there is an annotation @SendTo with destination “/topic/ping“.

        @MessageMapping("/ping")
	@SendTo("/topic/ping")
	public String ping(String message) throws Exception {
		System.out.println(message);
		return message;
	}

And also in the Message broker configuration SpringStompConfig there is a  piece of code as shown below

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
		config.enableSimpleBroker("/topic");
		config.setApplicationDestinationPrefixes("/app");
}

The line

config.enableSimpleBroker("/topic");

means that all subscription destination must be prefixed with “/topic“. So in the javascript code I am setting my subscription destination as “/topic/ping“.

           3. Sending a message.

I am sending a simple message as shown below:

// Send a message.
$scope.onStomp = function() {
	client.send('/app/ping', {}, $scope.info.msginput);
};

Here, if you look carefully, I am sending a message to the destination “/app/ping“. If you look carefully in the message controller StompController ,

        @MessageMapping("/ping")
	@SendTo("/topic/ping")
	public String ping(String message) throws Exception {
		System.out.println(message);
		return message;
	}

there is a mapping for the destination “/ping“. And also in the Message broker configuration SpringStompConfig,

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
		config.enableSimpleBroker("/topic");
		config.setApplicationDestinationPrefixes("/app");
}

I have configured that all messages sent to the websocket must be prefixed with “/app“. So the final destination becomes “/app/ping“.

    • Java client

Now in the java client  I wanted to send a message to the web client on a particular destination. The client code is simple.

package com.anupam.app.client;

import org.springframework.messaging.converter.StringMessageConverter;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandler;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;
import org.springframework.web.socket.client.WebSocketClient;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;

public class Client {

	static String url = &amp;amp;amp;amp;quot;ws://localhost:8080/springjavaconfig/ws/websocket&amp;amp;amp;amp;quot;;

	public static void main(String[] a) throws InterruptedException {
		WebSocketClient webSocketClient = new StandardWebSocketClient();
		WebSocketStompClient stompClient = new WebSocketStompClient(webSocketClient);
		stompClient.setMessageConverter(new StringMessageConverter());
		StompSessionHandler sessionHandler = new MyStompSessionHandler();
		stompClient.connect(url, sessionHandler);

		// Wait sometime.
		Thread.sleep(5000);
	}

	public static class MyStompSessionHandler extends StompSessionHandlerAdapter {

		@Override
		public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
			System.out.println(&amp;amp;amp;amp;quot;Connection successful.&amp;amp;amp;amp;quot;);
			session.send("<strong><span style="color: #339966;">/app/ping</span></strong>", "Hello");
		}
	}
}

Please note the url of our websocket.

static String url = "ws://localhost:8080/springjavaconfig/ws/websocket";

Please note that it starts with “ws” protocol and nothttp“. And I am sending a simple message to the destination “/app/ping“. Then the Message controller StompController receives the message at

        @MessageMapping("/ping")
	@SendTo("/topic/ping")
	public String ping(String message) throws Exception {
		System.out.println(message);
		return message;
	}

and routes to the destination “/topic/ping“. As the browser client is already subscribing to the destination it receives the message. And please do not forget to put a delay 

Thread.sleep(5000);

Please check out this video for a demo.

Session Management,REST+Oauth2+Spring

Well, REST applications are stateless, means they do not keep any client related data in Server.The server is stateless means that every server can serve any client at any time. The client’s state should never be stored anywhere in the Server. This is how the definition of REST goes.

Well, in my case, I had a requirement like this, “The user X must have single active session or in another words he can  log  in only at one place (browser or whatever).

So my idea is  as follows. As I am already using Oauth2 access token to access protected resources, I can use this access token as kind of session ID. When user X logs in to the application, first we check if he is holding an access token.If he is holding an access token, then we get this and delete it from the TokenStore and assign a new access token to him. As the access token he was holding previously has been deleted, he can no longer access to protected resources with that access token and thus invalidating his session. And thus, he can have only one active session.

Here is how it works,

d
Idea

 

So, the implementation is as follows.

Create the project

I am using Springboot to create the application. The project structure is as shown below.

Screenshot at 2016-07-31 10-33-43
Project structure.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.example</groupId>
	<artifactId>myoauth</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>oauthtest</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.3.6.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<angularjs.version>1.5.5</angularjs.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security.oauth</groupId>
			<artifactId>spring-security-oauth2</artifactId>
		</dependency>
		<!-- Web jars -->
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>angularjs</artifactId>
			<version>${angularjs.version}</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

Database access layer

For simplicity I am not using any database. Just a simple Map will hold our user data.

UserDAO.class

package com.anupam.dao;

import com.anupam.entity.UserVO;

public interface UserDAO {

	UserVO getUserByUsername(String username);

	void updateAccessToken(String username, String accessToken);

}

UserDAOImpl.class

package com.anupam.dao;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.springframework.stereotype.Repository;

import com.anupam.entity.UserVO;

@Repository
public class UserDAOImpl implements UserDAO {

	private static Map<String, UserVO> mapUsers;

	@PostConstruct
	public void init() {
		mapUsers = new HashMap<>();
		mapUsers.put("admin", new UserVO("admin", "1234", "ADMIN"));
		mapUsers.put("agogoi", new UserVO("agogoi", "1234", "ADMIN"));
	}

	@Override
	public UserVO getUserByUsername(String username) {
		UserVO user = mapUsers.get(username);
		return user;
	}

	@Override
	public void updateAccessToken(String username, String accessToken) {
		UserVO user = mapUsers.get(username);
		if (user != null) {
			user.setAccess_token(accessToken);
		}
	}
}

UserVO.class

package com.anupam.entity;

public class UserVO {

	String username, password, role, access_token;

	public UserVO(String username, String password, String role) {
		super();
		this.username = username;
		this.password = password;
		this.role = role;
	}

	public String getRole() {
		return role;
	}

	public void setRole(String role) {
		this.role = role;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getAccess_token() {
		return access_token;
	}

	public void setAccess_token(String access_token) {
		this.access_token = access_token;
	}

}

The Oauth2 configuration.

I have already written about the Oauth2 configuration in my previous post. Please do have a look into it.

AppSecurityConfig.class

package com.anupam.security;

import java.util.ArrayList;

import javax.servlet.ServletContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;

import com.anupam.dao.UserDAO;
import com.anupam.entity.UserVO;

@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	ServletContext ctx;

	@Autowired
	UserDAO userDAO;

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		// auth.inMemoryAuthentication().withUser("admin").password("1234").roles("USER");
		// auth.inMemoryAuthentication().withUser("agogoi").password("1234").roles("USER");
		auth.authenticationProvider(new AuthenticationProvider() {

			@Override
			public boolean supports(Class<?> authentication) {
				// TODO Auto-generated method stub
				return true;
			}

			@Override
			public Authentication authenticate(Authentication authentication) throws AuthenticationException {
				String username = authentication.getName();
				String password = authentication.getCredentials().toString();

				UserVO userVO = userDAO.getUserByUsername(username);
				if (userVO.getPassword().equals(password)) {

					// Set the current logged user.
					ctx.setAttribute("LOGGED_USER", userVO);

					UsernamePasswordAuthenticationToken u = new UsernamePasswordAuthenticationToken(userVO, password,
							new ArrayList<>());
					return u;
				} else {
					return null;
				}
			}
		});
	}

	@Override
	@Bean
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}

	/**
	 * Resource server.
	 * 
	 * @author anupam
	 *
	 */
	@Configuration
	@EnableResourceServer
	public static class ResourceServer extends ResourceServerConfigurerAdapter {

		@Override
		public void configure(ResourceServerSecurityConfigurer resources) {
			resources.resourceId("test");
		}

		@Override
		public void configure(HttpSecurity http) throws Exception {
			http.authorizeRequests().antMatchers("/login").permitAll();
			http.authorizeRequests().antMatchers("/data").authenticated();
		}

	}

}

AuthServer.class

package com.anupam.security;

import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.AuthenticationKeyGenerator;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

@Configuration
@EnableAuthorizationServer
public class AuthServer extends AuthorizationServerConfigurerAdapter {

	@Bean
	public TokenStore tokenStore() {
		InMemoryTokenStore ts = new InMemoryTokenStore();

		// Force to generate unique token. Otherwise it generates reusable
		// access token.
		ts.setAuthenticationKeyGenerator(new AuthenticationKeyGenerator() {

			@Override
			public String extractKey(OAuth2Authentication authentication) {
				return UUID.randomUUID().toString();
			}
		});
		return ts;
	}

	@Autowired
	private AuthenticationManager authenticationManager;

	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager);
	}

	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		clients.inMemory().withClient("web").secret("websecret").scopes("read", "write")
				.accessTokenValiditySeconds(3000)
				.authorizedGrantTypes("password", "refresh_token", "client_credentials");

	}

}

The simple controller.

MyController.class

package com.anupam.controller;

import java.util.Map;

import javax.servlet.ServletContext;

import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.anupam.dao.UserDAO;
import com.anupam.entity.UserVO;

@RestController
public class MyController {

	@Autowired
	TokenStore tokenStore;

	@Autowired
	ServletContext ctx;

	@Autowired
	UserDAO userDAO;

	@RequestMapping(path = "/data", method = RequestMethod.POST)
	public @ResponseBody String getData(@RequestBody String params) {
		return "You have successfully accessed the service with the access token.";
	}

	@RequestMapping(path = "/login", method = RequestMethod.POST)
	public Map<?, ?> doLogin(@RequestBody Map<String, Object> params) throws Exception {

		String username = (String) params.get("username");
		String password = (String) params.get("password");

		// Get the access token for the currently successful logged in user.
		// This method call sets the logged user in a context attribute in the
		// {@link AppSecurityConfig} class.
		Map<?, ?> map = getAccessToken(username, password);

		// Get logged user from the context.
		UserVO loggedUser = (UserVO) ctx.getAttribute("LOGGED_USER");

		// Now revoke the access token he is holding.
		// This means that if the user is logged in in some browser, he will no
		// longer be able to access
		// the secure REST services as we are deleting his access token.
		if (loggedUser.getAccess_token() != null && !loggedUser.getAccess_token().equals("")) {
			revokeAccessToken(loggedUser.getAccess_token());
		}

		// Now update the user with the new access token.
		loggedUser.setAccess_token((String) map.get("access_token"));

		// We do not need any information of the logged in user.
		// So delete this information for the context attribute.
		ctx.removeAttribute("LOGGED_USER");

		return map;
	}

	private Map<?, ?> getAccessToken(String username, String password) throws Exception {
		String authUrl = "http://localhost:8080/app/oauth/token?";
		StringBuilder authParams = new StringBuilder("client_id=web&client_secret=websecret&grant_type=password");
		authParams.append("&username=").append(username).append("&password=").append(password);

		String url = authUrl.concat(authParams.toString());
		ResponseEntity<String> response = new TestRestTemplate("web", "websecret").postForEntity(url, null,
				String.class);
		String responseText = response.getBody();

		Map<?, ?> map = new ObjectMapper().readValue(responseText, Map.class);
		return map;
	}

	private void revokeAccessToken(String token) {
		OAuth2AccessToken accessToken = tokenStore.readAccessToken(token);
		if (accessToken != null) {
			tokenStore.removeAccessToken(accessToken);
		}
	}

}

The main class.

Application.class

package com.anupam;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}

The tests

Lets test the application. I am using Postman to test.

In the figure 1, I have logged in using username=admin and password=1234. I got the access token and with the access token I have accessed a protected resource in the path /data as shown in figure 2.

22
Figure 1

After successful login, I have updated the user with this access token granted.If you look carefully there is a property called access_token in the UserVO.

Access the protected resource in the path /data.

33
Figure 2

 

Now lets login with the same username and password. (The right hand side postman window)

44
Logged in with same username and password. (Right window)

Now what exactly happened in the background ?

When I logged in with the same username and password, in the background, I searched for the user and checked if there was any existing access token associated with him. Yes, I have found an access token associated with him as the user had previously logged into the application. So, I get that access token and delete from the TokenStore. It means that in the previously logged in session, the user no longer can use that access token and thus his session is invalidated.

How to prove it ?

Lets access the resource at the path /data in the previously logged in session.

55
Token is not valid anymore.

So, I get a message saying that the access_token is no longer valid.

Lets access the protected resource in the newly logged in session.

66

We can successfully access the protected resource.

And thus we can let only active session per user.

Thank you for reading my blog.