Archive for December, 2012

30
Dec

SOAP Web-service by means of Spring-WS

Posted by eugene as Spring Framework, Web Services

Webservices

Once I’ve got a task to start developing of the web services and had the sources of a simple project without any explanation. The project, for sure couldn’t be laundched. What is Spring and how it works, I couldn’t also imagine. I also couldn’t find any adequate articles of developing the web services by means of Spring – neither Russian, nor English. I had to learn everything by myself, and it appeared all wasn’t so awful. And just recently I decided to see what new opportunities were added in Spring since then, and to update old services what entailed writing of this article.

This article is the guide of simple Web service development that uses SOAP protocol.

Thus we’ll write the simple service that accepts the username and sends a greeting and the current time on the server.

what will we need?

Preparation for work

Let’s create a new Web application project. In Eclipse this will be: “File => New => Dynamic Web Project”. I’ve called the project HelloService. Then let’s copy libraries from Spring, XMLBean, wsdl4j, commons-logging into the WEB-INF/lib project catalogue. If you wish you can add them to the server libraries in order not to move them with each application.

Creation the WSDL scheme

In fact, WSDL scheme is intended to describe the service. We won’t certainly create it manually. The scheme will be generated automatically by Spring, but more on that will be mentioned later.

Defining input and output

Input data:

  • String name

Output data:

  • Greeting string;
  • Current time.

Creating the description of input and output data

Let’s create HelloService.xsd file in the WEB-INF catalogue. This file will be necessary for generating WSDL scheme and creating the corresponding Java classes.

File contents:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/HelloService" elementFormDefault="qualified">
  <element name="ServiceRequest">
    <complexType>
      <sequence>
        <element name="name" type="string" maxOccurs="1" minOccurs="1"/>
      </sequence>
    </complexType>
  </element>
  <element name="ServiceResponse">
    <complexType>
      <sequence>
        <element name="hello" type="string" maxOccurs="1" minOccurs="1"/>
        <element name="currentTime" type="time" maxOccurs="1" minOccurs="1"/>
      </sequence>
    </complexType>
  </element>
</schema>

The targetNamespace attribute is used namespace. I.e. all the created objects will be located in the org.example.hellpService package.

The ServiceRequest and ServiceResponse describe input and output data correspondly (request/answer).

The minOccurs and maxOccurs attributes define the number of repeats of the given component within one single element. If not to specify these options, then by default they are considered to be equal to 0. It’s necessary to specify minOccurs = 0 for the optional component. When the number of components is unlimited: maxOccurs = unbounded.

You can read about XML schemes in more details here.

Creating JavaBeans

Based on the created scheme we’ll create Java classes. To do this, create build.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<project name="imsjob" default="build" basedir=".">
<property name="WS_HOME" value="C:\AST\lib\standart"/>
<property name="encoding" value="UTF-8"/>
<path id="xbean.classpath">
    <fileset dir="${WS_HOME}">
      <include name="*.jar"/>
    </fileset>
  </path>
    <taskdef name="xmlbean" classname="org.apache.xmlbeans.impl.tool.XMLBean" classpathref="xbean.classpath" />
      <target name="init">
    <echo message="Start init"/>
  </target>
    <target name="build" depends="init">
    <xmlbean schema="HelloService.xsd" destfile="lib\helloservice.jar" classpathref="xbean.classpath"/>
  </target>
</project>

The WS_HOME parameter should point on the catalogue where XMLBeans located. HelloService.xsd is the path to the created scheme. lib\helloservice.jar is the created java-library.

Then let’s run Ant-build (I hope you’ve already installed it). In Eclipse you can run it so: right-clicking build.xml=> Run As => Ant Build. If via the command line: ant -buildfile build.xml. And then just wait for the build completion. After that, you can check the WEB-INF\lib project catalogue for the presence of the corresponding library (helloservice.jar).

Service realization

Create interface and service class

Service interface:HelloServiceImpl.java:

package org.example;
import java.util.Calendar;
public interface HelloService {
  public String getHello(String name) throws Exception;
  public Calendar getCurrentTime();
}

Service realization: HelloServiceImpl.java:

package org.example;
import java.util.Calendar;
import org.springframework.stereotype.Service;
@Service
public class HelloServiceImpl implements HelloService {
  public String getHello(String name) throws Exception {
    return "Hello, " + name + "!";
  }
  public Calendar getCurrentTime() {
    return Calendar.getInstance();
  }
}

I think there’s no need to comment the code. The only thing that people which haven’t met Spring before could have questions what is the @Service annotation. But I’ll talk about it a bit later.

Endpoint

Endpoint is the class which will be responsible for the processing of input requests (like the entry point).

Let’s create the HelloServiceEndpoint.java file:

package org.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.example.helloService.ServiceRequestDocument;
import org.example.helloService.ServiceRequestDocument.ServiceRequest;
import org.example.helloService.ServiceResponseDocument;
import org.example.helloService.ServiceResponseDocument.ServiceResponse;
 
@Endpoint
public class HelloServiceEndpoint{
  private static final String namespaceUri = "http://www.example.org/HelloService";
  private HelloService helloService;
  @Autowired
  public void HelloService (HelloService helloService) {
    this.helloService = helloService;
  }
    @PayloadRoot(localPart = "ServiceRequest", namespace = namespaceUri)
  public ServiceResponseDocument getService(ServiceRequestDocument request) throws Exception {
    ServiceRequestDocument reqDoc = request;
    ServiceRequest req = reqDoc.getServiceRequest();
    ServiceResponseDocument respDoc = ServiceResponseDocument.Factory.newInstance();
    ServiceResponse resp = respDoc.addNewServiceResponse();
 
    String userName = req.getName();
    String helloMessage = testNewService.getHello(userName);
    Calendar currentTime = testNewService.getCurrentTime();
 
    resp.setHello(helloMessage);
    resp.setCurrentTime(currentTime);
    return respDoc;
  }
}

So what is done here?

The @Endpoint annotation exactly defines that this class will process the input requests. namespaceUrl is the same namespace that was specified during the creation of xml scheme.

Now let’s go a bit back and remember about the @Service annotation. Without going into details in order not to overload the reader with the extra information, the annotation tells Spring to create the appropriate object. The @Autowired annotation serves for injection (automatic replacement) of the corresponding object. Certainly when building simple application there is no sense in using these annotations but I decided not to exclude them in this example.

Hence, let’s go forward. The @PayloadRoot annotation defines before the method by receiving of which request this method will be called. In our case, it’s a “ServiceRequest”.

In all the rest everything should be clear. Pay attention that ServiceRequest, ServiceResponse and so on are exactly those classes which have been created on the basis of our xml scheme.

Spring configuration of the service

Here is almost the completion. Let’s create the service-ws-servlet.xml.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:sws="http://www.springframework.org/schema/web-services"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
  <context:component-scan base-package="org.example" />
  <sws:annotation-driven />
 
  <bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">
<property name="marshaller" ref="marshaller" />
<property name="unmarshaller" ref="marshaller" />
  </bean>
 
  <bean id="marshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller"/>
 
  <sws:dynamic-wsdl id="HelloService" portTypeName="service" locationUri="/HelloService" >
    <sws:xsd location="/WEB-INF/HelloService.xsd" />
  </sws:dynamic-wsdl>
</beans>

sws:annotation-driven – tells exactly about that annotations are used in this project. And context:component-scan points on the package where annotation searching will be performed, by the same time searching is performed in subpackages as well.

Both subsequent beans will always be constant. Their sense is to receive and to convert the request from XML into Java object and further reverse conversion.

sws:dynamic-wsdl is responsible for the automatic generation of WSDL-based document created by XML scheme. location points on the path to scheme. locationUrl is the address (relating to container) which will be available for WSDL scheme. In my case WSDL is available over the following address: http://localhost/HelloService/HelloService.wsdl.

Deployment descriptor

And finally, the last one. In the WEB-INF catalogue let’s modify and create the web.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <display-name>HelloService</display-name>
  <description>HelloService</description>
  <servlet>
    <servlet-name>service-ws</servlet-name>
    <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
    <init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
    </init-param>
  <servlet-mapping>
    <servlet-name>service-ws</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

I won’t describe this file, most of them you should know. In fact it shouldn’t change for simple projects. It’s worth to note that the servlet name should correspond to the file name of Spring configuration of the service-ws-servlet.xml service.

Then, let’s deploy the application on the server. Creation of the service is completed at this stage. If we haven’t missed anything, the service should function well.

The very first sign of correct performance is the created WSDL scheme. In order to check it, just go over the address of this scheme: (http://localhost/HelloService/HelloService.wsdl) and look: the xml file should be displayed there. If nothing displayed or any other error occurred, re-read the whole article and search what was done incorrectly.

For further verification, we need soapUI (I have version 3.0.1).

Let’s install and run it, and then create a new project: File => New soapUI Project.

In the Initial WSDL/WADL field insert the link to WSDL scheme: (http://localhost/HelloService/HelloService.wsdl).

Let’s open the necessary request in the created project.

request

In the Name field type the name and press the “Send request” button.

name

As a result we get the answer from the server with the greeting and current time.

answer

If something went wrong then read this article once again.

What’s next?

Then you should write client for the web service. But it’s the material for another article which could be probably written later if this material will be interesting for anyone.

28
Dec

Integration tests with Maven, JUnit and Spring

Posted by eugene as Unit Testing

Unit tests is a good thing but my point is that it’s wrong to rely just on them. Sometimes it’s very important to check how several classes work and sometimes how do application leyers work together.

Our application actively uses Spring and it means the integration tests also should work with the Spring context.

Often these tests can be time consuming, even if you use the in-memory database (by the way I’ve checked why – we have too many JPA entities with multiple properties in each one and the Hibernate initialization, exactly it takes dozens of seconds!)

So we need to make sure that to do so that these tests wouldn’t have been implemented by default unlike conventional unit tests and wouldn’t have been implemented during the build.

The plan is as follows:

  • 1. Write the services divided into two application layers
  • 2. Join them by Spring
  • 3. Write the test by using JUnit for interaction of these services (real ones without any mocks)
  • 4. Make sure this test is not run by default during the build
  • 5. Profit!

1. Writing services divided into two application layers

Why two layers? I prefer to divide the business logic into the layers (for example, the persistency layer) in order the code won’t turn into spaghetti. Layers have hierarchy – which one can call and by dividing the layers into the different maven projects I’m checking that there are no forbidden relationships.

Hence, let’s create pom.xml of the whole application with the dependencies which are necessary for all:

<?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.mycompany</groupId>
    <artifactId>myapp</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
 
    <name>myapp</name>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-version>3.1.0.RELEASE</spring-version>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring-version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>
    </dependencies>
 
    <modules>
        <module>backend</module>
        <module>frontend</module>
        <module>gui</module>
    </modules>
 
</project>

It contains three modules – gui, frontend and backend (two layers of business logics).

Here is pom.xml for frontend:

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.mycompany</groupId>
    <artifactId>myapp</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <groupId>com.mycompany</groupId>
  <artifactId>frontend</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>frontend</name>
    <dependencies>
        <dependency>
            <groupId>com.mycompany</groupId>
            <artifactId>backend</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

As you can see it depends on backend and all the rest receives from the parent pom.

Here is pom.xml for backend:

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.mycompany</groupId>
        <artifactId>myapp</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.mycompany</groupId>
    <artifactId>backend</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>backend</name>
</project>

Let’s create the following in the backend/src/main/java/com/mycompany/service/backend directory:

IBackendService1.java:
package com.mycompany.service.backend;
 
public interface IBackendService1 {
    String computeSecretString();
}
BackendService2.java:
 
package com.mycompany.service.backend;
 
public interface IBackendService2 {
    int computeSecretNumber();
}
BackendService1.java:
 
package com.mycompany.service.backend;
 
public class BackendService1 implements IBackendService1 {
    @Override
    public String computeSecretString() {
        return "James Bond";
    }
}
BackendService2.java:
 
package com.mycompany.service.backend;
 
public class BackendService2 implements IBackendService2 {
    @Override
    public int computeSecretNumber() {
        return 7;
    }
}

Let’s create the following in the frontend/src/main/java/com/mycompany/service/frontend directory:

IFrontendService.java:

package com.mycompany.service.frontend;
 
 
public interface IFrontendService {
    String getAgent();
}

FrontendService.java:

package com.mycompany.service.frontend;
 
 
import com.mycompany.service.backend.*;
 
public class FrontendService implements IFrontendService {
 
    private IBackendService1 backendService1;
    private IBackendService2 backendService2;
 
    public FrontendService(IBackendService1 backendService1, IBackendService2 backendService2) {
        this.backendService1 = backendService1;
        this.backendService2 = backendService2;
    }
 
    @Override
    public String getAgent() {
        return backendService1.computeSecretString()+backendService2.computeSecretNumber();
    }
}

2. Joining them by Spring

backend/src/main/resources/backend-beans.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
 
    <bean id="names_provider" class="com.mycompany.service.backend.BackendService1"/>
    <bean id="secret_service" class="com.mycompany.service.backend.BackendService2"/>
 
</beans>

frontend/src/main/resources/frontend-beans.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       ">
    <import resource="classpath:backend-beans.xml"/>
 
    <bean id="agent_service" class="com.mycompany.service.frontend.FrontendService">
        <constructor-arg index="0" ref="names_provider"/>
        <constructor-arg index="1" ref="secret_service"/>
    </bean>
 
</beans>

3. Let’s write the test by using JUnit for interaction of these services (real ones without any mocks)

In the frontend/src/test/java/com/mycompany/integration directory

FrontendServiceTest.java:

package com.mycompany.integration;
 
 
import com.mycompany.service.frontend.IFrontendService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
import static org.junit.Assert.assertTrue;
 
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@ContextConfiguration(locations = {"classpath:frontend-beans.xml"})
public class FrontendServiceTest {
 
    @Autowired
    IFrontendService frontendService;
 
    @Test
    public  void testBond() {
        String agent = frontendService.getAgent();
        assertTrue("It should be Bond", agent.contains("Bond"));
    }
 
}

Pay attention on the annotations:

@RunWith(SpringJUnit4ClassRunner.classMode.AFTER_EACH_TEST_METHOD) – runs tests with the Spring “launcher”

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) – will create Spring context from scratch for each test method

@ContextConfiguration(locations = {“classpath:frontend-beans.xml”}) – where to take beans

there’s also @ActiveProfiles(profiles = “local”) – if you don’t use profiles.

@AutoWired will inject the beans into the test class. If you have more than one bean realizing the definite interface you can replace it on @Resource(name = “session-operations”)

4. Let’s do so that this test won’t run by default during the build

Let’s add the following into pom.xml of the whole application:

 <properties>
        ...
        <systest.package>**/com/mycompany/integration/**</systest.package>
    </properties>
 
 <build>
       ....    
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.5</version>
                <configuration>
                    <excludes>
                        <exclude>${systest.package}</exclude>
                        <exclude>**/*$*</exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

Now the test won’t launch during the build. (We’ve also mentioned the inner classes are not tests).

And to have an opportunity to run it not only by name, let’s add the profile where there’s no such exclude:

<profiles>
        <profile>
            <id>systest</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <version>2.5</version>
                        <configuration>
                            <excludes>
                                <exclude>**/*$*</exclude>
                            </excludes>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

Now all the tests located in com.mycompany.integration won’t run during the build and to launch them it’s necessary to install the “systest” maven profile, for example as follows:

mvn -P=systest test

5. Profit!

26
Dec

Creation of simple application in Java

Posted by eugene as Java

Good day!

This article is about the organization of the simple application in Java for beginners who has already learnt the concept of the object approach. But maybe it will be also interesting for the experienced developers.

The novice developers frequently ask the question: “How should I start creating the application”, which classes to use and so on.

You should not treat this article as an example of “Hellow World” for the beginners learning Java language and object-oriented approach. It is assumed that the reader is familiar with the language of Java however he would have questions above.

We give the answer to these questions in this article.

In order to build an application gradually, using the concepts of object-oriented approach, we will provide all the application elements in the form of the objects of the corresponding classes. Hence, the application will also be a separate class. In order to run the application, we’ll create an instance of it.

Now there’re some more details..

At first the Application class is created – it will be the model of the entire application.

public class Application {
}

Then let’s create the input point in the application – the main method:

public class Application {
    public static void main(String[] args) {
    }
}

This method is implemented when running Java specifying the basis class (Application). We create the application instance in it, initialize and then run it. We’ll use the init and run methods for this:

public class Application {
    public void init() {
    }
 
    public void run() {
    }
 
    public static void main(String[] args) {
        Application application = new Application();
        application.init();
        application.run();
    }
}

Let’s do the necessary application initialiazation in the init method. The main application code is located in the run method.

You may not use the init mehtod (it’s up to you), however we believe that our application has two stages – initialization and start.

All the other elements of the application can be divided into classes and types of the model (windows, panels). For example, suppose we create a simple credit calculator. The the CreditCalculator class will be the model of the calculator. We will initialize calculator in the init method and calculate in run:

public class Application {
    private CreditCalculator calculator;
 
    public void init() {
        calculator = new CreditCalculator();
    }
 
    public void run() {
        calculator.setAmount(500000);
        calculator.setYears(3);
        calculator.calculate();
        System.out.println("Месячный платеж: " + calculator.getMonthlyPayment());
    }
 
    public static void main(String[] args) {
        Application application = new Application();
        application.init();
        application.run();
    }
}

Thus, the creation of the application can be started with the creation of the Application class and then adding all the necessary model classes with which you want to work.

Now, how to start the application

We will proceed out of that you use the Eclipse development environment, Intellij IDEA or NetBeans. And the Application class is created in it. In these environments you should invoke the context menu and click Run… or Run As Application in the editor of the Application class.

But still the same – launching application from the environment was not our goal, and the goal was to understand with which classes you can start building applications.

The article is written based on the Procode podcast

RSS: procode.podomatic.com/rss2.xml

iTunes: itunes.apple.com/ru/podcast/procode/id529972125

The appeal to the cool developers is not swear – you know everything! But better swear – then it will be clear what is wrong.

The appeal is to leave the constructive comment before the assessment of the article.

24
Dec

Authorization on the website via API of social networks with integration into Spring Security

Posted by eugene as Spring Framework, Web Applications

I’ve decided to implement authorization (registration) on the prepared website and to identify users with the help of the social network developer instrument (Social Networks REST API) – tge subject is not far innovative, widely used and very easy to use. I won’t list all the benefits and convenience of using such functionality on their websites, but I want to admit that I am very happy not to remember passwords for each website (even I have a couple of standard used), not to engage in long and boring registration with sending mails and acknowledgements, and do not deal with captchas again and so on.

The API data functionality is rather primitive, simple technology and implementation is quite similar and simple. But when you familiarize with the technology, it is not only enough to have API documentation and social networking examples. In addition, as described in the topic, the used language is Java which automatically reduces the amount of useful information. And there’s no too much information in RU net either. You can follow the path of the least resistance and use the third-party RESTful products, but a) it doesn’t give full understanding of the process, and b) reduces the switching properties of the desired process; c) the third-party product research often can be more difficult that the development of its implementation. While ease of use of such third-party product can facilitate the development at times. However I’ve put the emphasis on making the most control over all processes in this review even at the expense of universality (we “fasten” specific functionality to the particular site, and only a few make the versatile product “for all life occasions” out of it). In addition, I am interested not only how to implement the authentication of users, but also to invent it into the project security system which is provided by the Spring Security 3 framework.

The used set of platforms and tools is: Spring Core 3.1, Spring MVC 3.1, Spring Security 3.1, Hibernate 4.1. The implementation project is foreig, therefore a set of introduced social networks is standard “for them” – Facebook, Twitter, Google+, Linkedin.

I want to admit that a ready “out of the box” project is available in the Spring package – Spring Social (for now is release 1.0.2) which is currently encapsulated in a wonderful Spring-framework product. Surely it would have been a professional solution but our task is to control everything and make the process as transparent for understanding as possible. And it’s not so good with Social itself.

1. Model.

I’ve chosen a little risky and controversial way, combining the user and POJO, and UserDetails, and Entity in the object. In terms of the programming approach this is wrong but: a) it’s very convenient; and b) saves the creation of severeal layers which saves us to make separate POJO+Entity, separately UserDetails and separately DTO which actually duplicates the content.

The proposed scheme of model construction looks like the following:

Model

I’ve identified two layers (AuthUser and DataUser) in order not to interfere with authorization logic with the business logic of the project: both the visitor and the manager and whoever else – will be authenticated the same but will have their own set of properties. For example, in my project there’re Jobseekers and Employers, the same way get to the website but they have completely different structure of the model.

As for the separation of structure within the layers, this is obvious – a set of the received fields from Facebook, Twitter and so on, and especially during the standard authorization, is so different that to create the entire terribly stretched structure for everything is just silly and in terms of building a database – redundant. As per scalability, when adding a new service provider the work with such a structure would be extremely uncomfortable.

Below are the listings of some objects, and also the used enum classes.

AuthUser.java:

@ Entity
    @ Table(name = "auth_user")
    @ Inheritance(strategy = InheritanceType.JOINED)
    public class AuthUser implements Serializable, UserDetails {
        @ Id
        @ Column(name = "id")
        @ GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
 
        @ Column(name = "identification_name", length = 64, nullable = false)
        private String identificationName;
 
        @ Enumerated(EnumType.STRING)
        @ Column(name = "type", nullable = false)
        private AuthorityType type;
 
        @ Column(name = "binary_authorities", nullable = false)
        private Long binaryAuthorities;
 
        @ Column(name = "enabled", nullable = false, columnDefinition = "tinyint")
        private Boolean enabled;
 
        @ Transient
        private Set<Authority> authorities;
 
        @ OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
        @ Cascade({CascadeType.ALL})
        @ JoinColumn(name="user_id")
        private User user;
 
        @ Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            authorities = EnumSet.noneOf(Authority.class);
            for (Authority authority : Authority.values())
            		if ((binaryAuthorities & (1 << authority.ordinal())) != 0)
                    authorities.add(authority);
            return authorities;
        }
        public void setAuthority(Set<Authority> authorities) {
            binaryAuthorities = 0L;
            for (Authority authority : authorities)
                binaryAuthorities |= 1 << authority.ordinal();
        }
        @ Override
        public String getPassword() {
            return type.name();
        }
        @ Override
        public String getUsername() {
            return identificationName;
        }
        @ Override
        public boolean isAccountNonExpired() {
            return true;
        }
        @ Override
        public boolean isAccountNonLocked() {
            return true;
        }
        @ Override
        public boolean isCredentialsNonExpired() {
            return true;
        }
 
        //getters/setters
    }

AuthorityType.java:

public enum AuthorityType implements Serializable {
        SIMPLE, FACEBOOK, TWITTER, GOOGLE, LINKEDIN;
    }

Authority.java:

public enum Authority implements GrantedAuthority {
        NEW_CUSTOMER, CUSTOMER, ADMINISTRATOR;
 
        @ Override
        public String getAuthority() {
            return toString();
        }
    }

FacebookAuthUser.java:

@ Entity
    @ Table(name = "facebook_auth_user")
    public class FacebookAuthUser extends AuthUser {
        @ Column(name = "first_name", length = 32)
        private String firstName;
 
        @ Column(name = "last_name", length = 32)
        private String lastName;
 
        @ Column(name = "email", length = 64)
        private String email;
 
        @ Column(name = "token", length = 128)
        private String token;
 
        //any number of available properties
        //getters/setters
    }

TwitterAuthUser.java:

@ Entity
    @ Table(name = "twitter_auth_user")
    public class TwitterAuthUser extends AuthUser {
        @ Column(name = "screen_name", length = 64)
        private String screenName;
 
        @ Column(name = "oauth_token", length = 80)
        private String oauthToken;
 
        @ Column(name = "oauth_token_secret", length = 80)
        private String oauthTokenSecret;
 
        //any number of available properties
        //getters/setters
    }

SimpleAuthUser.java:

@ Entity
    @ Table(name = "simple_auth_user")
    public class SimpleAuthUser extends AuthUser {
        @ Column(name = "password", length = 40, nullable = false)
        private String password;
 
        @ Column(name = "uuid", length = 36, nullable = false)
        private String uuid;
 
        @ Override
        public String getPassword() {
            return password;
        }
 
        //getters/setters
    }

As you can see, it’s not all enough without the slightest “magics”:

  • I don’t want to do one more structure (table) for storing user roles and to miss the opportunity to assign a user multiple roles changing a set of roles for another one is weird. Therefore I store a binary representation of the set of roles in the database, and I feed the set to Spring Security. The main thing is to remember to make a transformation while reading from the database. Ideologically it’s not correct to hold the transformation mechanism in POJO, it is necessary to leave it in the controller or DAO, but let’s assume it costs of publication.
  • The type field (AuthorityType enum) – it doesn’t carry the special need rather to visualize data in the database, plus it’s easier to use user.getType() in the representation rather than investigate the belonging to one of the classes – user insteadof TwitterAuthUser, even though it’s not important.
  • The UserDetails interface requires to implement a number of methods. In particular, identificationName (and getUsername()) is the field that stores the identifiers: FacebookID for Facebook, TwitterID for Twitter, nickname or email for the standard authorization. The getPassword() method in my case returns that same type, further it will be used by Spring Security in order to form hash cookies in the RememberMe mechanism. In order to improve the project security in every class you can redefine this method by assigning the secure data to it, as I’ve done this in the SimpleAuthUser class. For others it can be tokens or secret tokens. What to do next with the methods and potentially corresponding to them isAccountNonExpired, isAccountNonLocked, isCredentialsNonExpired properties – to decide as appropriate of using such data, in this review I don’t use them drowning return true.

As you can see in the scheme and code, I’ve decided to use the lazy dependency between the objects of different layers, even though they are interrelated as “one-to-one”. There’re two objectives: 1) AuthUser often twitches by framework in the controller and view, and there’s no great desire to pull the dependent structure all over itself, moreover it can be quite extended and massive (I have almost 5-6 EAGER dependencies in the Jobseeker tables of the project, not counting LAZY – these are both phone numbers, and address, and proffessions and so on), that’s why in my opinion the safe side will not prevent. 2) you shouldn’t forget that these layers are related to different logics layers: AuthUser is twitching by the Spring Security framework, and in parallel the changes can occur in DataUser, and there’s no much desire to engage in constant tracking and updating. I agree that the decision is dispute and it does not claim to be definitive. Perhaps it is necessary to link the contrary, thus the listed problems will be gone, but the business logic, you can always pull the authorization bean. It’s left up to the developers.

What’s related to the DataUser class and the dependent these are the simple POJO classes, directly DataUser contains common for all properties (e.g. id, firstName, lastName, email, location) and the rest expand it by adding the specific for them properties (it’s impractical to show the listings).

2. Controller.

Basically in terms of authentication and authorization there’s no much difference, and verious network providers predispose these terms in their own way. However, I clearly distinguish two concepts in this report – registration and the authorization itself or input (both are based on the authorization in the social network provider). For example, when participating on forum or submitting comments you simply should log in – whether it is the first entry or the hundredth. In my division for registration and basic authorization I am chasing the need to create a user model in the application for registartion. And while it might be easier to implement – at the entrance check – whether such person exists or not – and create the user structure in case of the first entry. But a) there exists a standard registration and it’s logical to make visual division “here is one thing and there another one” (notorious usability); b) how it’s not disappointing but API of the social networks are not agreed to provide information about their clients – for example, Facbook API provides email, name, gender, location; Twitter API provides screen_name, which may not necessarily be “a name or surname”, doesn’t provide email (they have a position to clearly distinguish reality and virtuality); Google+ API provides name, last name, email but nothing about location; LinkedIn API – name, last name, gender, location but doesn’t provide email. Since my project is very closely tied to the personal visitor data (project for the recruiting company), together with the registration I point to the need to fill in some fields (initially except the Facebook users all had to specify something, now is simplified and such need exists only for Twitter users, though I do not exclude a complete failure and the filling of fields will be simply just needed, for example when trying to get into the “zone”). Therefore my implementation is a bit overblown, though it only helps to understand better the mechanism of authentication.

I want to recall that it’s necessary to create your own application in every social network and to use its settings for work (or testing). This is developers.facebook.com/apps for Facebook, dev.twitter.com/apps for Twitter, code.google.com/apis/console for Google+, www.linkedin.com/secure/developer for LinkedIn. When creating an application there exist three important parameters which are available in every provider – key (API key, Consumer key, Client ID), secret key (App Secret, Consumer Secret, Client Secret, Secret key) and the redirect address (say, until recent time some providers’ localhost redirect didn’t work properly, but for now all is tested – all work with the address type of http://localhost:8080/myproject). There you can configure other settings, including the logo of the application, however, Linkedin requires the SSL link to the image (strange wish).

Facebook and Google+ have been using new OAuth 2 protocol, Twitter and LinkedIn are still on the older OAuth protocol (Google+ also supported the first OAuth version till the 20th of April, 2012). Due to my descretion (although I can’t imagine that there could be another opinion) it’s immeasurably easier and more convenient to work with OAuth 2, however, despite the fact that it’s quite popular, it still hasn’t been approved as standard. The concept of its work is rather primitive (the most popular scheme).

pic2

Thus, a user clicks one of the registration buttons on the web page:

capt

(and I don’t leave any “extra” functionality on the page, just a button with the address like www.myproject.com/registration/facebook and so on), the request will get into the controller (for Facebook).

@ RequestMapping(value = "/registrate/facebook", method = RequestMethod.POST)
    public ModelAndView facebookRegistration() throws Exception {
        return new ModelAndView(new RedirectView(FACEBOOK_URL + "?client_id=" + FACEBOOK_API_KEY +
            + "&redirect_uri=" + FACEBOOK_URL_CALLBACK_REGISTRATION +
            + "&scope=email,user_location&state=registration", true, true, true));
    }

The scope parameters can be found at developers.facebook.com/docs/authentication/permissions (for Twitter – dev.twitter.com/docs/platform-objects/users, Google+ – developers.google.com/accounts/docs/OAuth2Login#userinfocall, LinkedIn – developer.linkedin.com/documents/profile-fields), I’ve put only the couple of examples. The redirect_uri domain must match the registered address of the date application. state is the “free” parameter which I use as the semaphor for the further actions – registration, signin, autosignin.

Then the user is being redirected to the root Facebook authorization page where it will allow the application to use its data, and if the resolution are going out of the basic scopes, they will be listed in the authentication window.

After authorization our controller with the FACEBOOK_IRL_CALLBACK_REGISTRATION mapping gets a call (in any client’s decision – authenticate, cancel, return). Spring MVC allows us to filter the requests by mapping at once (in this case here is the mapping of my project):

@ RequestMapping(value = "/callback/facebook", method = RequestMethod.GET)
    public class FacebookController extends ExternalController implements Constants {
        @ RequestMapping(value = "/registration", params = "code")
        public ModelAndView registrationAccessCode(@ RequestParam("code") String code, HttpServletRequest request) throws Exception {
            String authRequest = Utils.sendHttpRequest("GET", FACEBOOK_URL_ACCESS_TOKEN, new String[]{"client_id", "redirect_uri", "client_secret", "code"}, new String[]{FACEBOOK_API_KEY, FACEBOOK_URL_CALLBACK_REGISTRATION, FACEBOOK_API_SECRET, code});
            String token = Utils.parseURLQuery(authRequest).get("access_token");
    String tokenRequest = Utils.sendHttpRequest("GET", FACEBOOK_URL_ME, new String[]{"access_token"}, new String[]{token})
            Map<String, Json> userInfoResponse = Json.read(tokenRequest).asJsonMap();
            String email = userInfoResponse.get("email").asString().toLowerCase();
            String id = userInfoResponse.get("id").asString();
            //verifying ... is new? is email in DB?
            //creating objects
            Customer customer = new Customer();
            customer.setEmail(email);
            //...
            customerer = (Customerer) userDAO.put(customer);
            FacebookAuthUser user = new FacebookAuthUser();
            user.setFirstName(firstName);
            //...
            user.setIdentificationName(id);
            user.setToken(token);
            user.setType(AuthenticationType.FACEBOOK);
            user.setEnabled(true);
            user.setAuthority(EnumSet.of(Authority.CUSTOMER));
            user.setUser(customer);
            authenticationDAO.put(user);
            return new ModelAndView(new RedirectView("/registrate.complete", true, true, false));
        }
 
        @ RequestMapping(value = "/registration", params = "error_reason")
        public ModelAndView registrationError(@ RequestParam("error_description") String errorDescription, HttpServletRequest request, HttpServletResponse response) {
            //return client to registration page with errorDescription
            return new ModelAndView(new RedirectView("/registrate", true, true, false));
        }
        //will signin and signinError
    }

For convenience and the unitary using, here is a couple of static methods of the Utils class used in this listing:

public static String sendHttpRequest(String methodName, String url, String[] names, String[] values) throws HttpException, IOException {
        if (names.length != values.length) return null;
        if (!methodName.equalsIgnoreCase("GET") && !methodName.equalsIgnoreCase("POST")) return null;
        HttpMethod method;
        if (methodName.equalsIgnoreCase("GET")) {
            String[] parameters = new String[names.length];
            for (int i = 0; i < names.length; i++)
                parameters[i] = names[i] + "=" + values[i];
            method = new GetMethod(url + "?" + StringUtils.join(parameters, "&"));
        } else {
            method = new PostMethod(url);
            for (int i = 0; i < names.length; i++)
                ((PostMethod) method).addParameter(names[i], values[i]);
            method.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        }
        new HttpClient().executeMethod(method);
        return getStringFromStream(method.getResponseBodyAsStream());
    }
    public static Map<String, String> parseURLQuery(String query) {
        Map<String, String> result = new HashMap<String,String>();
        String params[] = query.split("&");
        for (String param : params) {
            String temp[] = param.split("=");
            try {
                result.put(temp[0], URLDecoder.decode(temp[1], "UTF-8"));
            } catch (UnsupportedEncodingException exception) {
                exception.printStackTrace();
            }
        }
        return result;
    }

Constants:

final public static String FACEBOOK_API_KEY = "XXXXXXXXXXXXXXXX";
    final public static String FACEBOOK_API_SECRET = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    final public static String FACEBOOK_URL = "https://www.facebook.com/dialog/oauth";
    final public static String FACEBOOK_URL_ACCESS_TOKEN = "https://graph.facebook.com/oauth/access_token";
    final public static String FACEBOOK_URL_ME = "https://graph.facebook.com/me";
    final public static String FACEBOOK_URL_CALLBACK_REGISTRATION = SITE_ADDRESS + "/callback/facebook/registration";
    final public static String FACEBOOK_URL_CALLBACK_SIGNIN = SITE_ADDRESS + "/callback/facebook/signin";

Everyone can use JSON libraries up to its own discretion, I used the mjson library (http://sharegov.blogspot.com/2011/06/json-library.html) – small, convenient and without serialization.

As you can see, the process is simple and should not cause any special problems. I’d like to note that Facebook provides the location parameter and its value can be “pulled” to Google Maps API (by following http://maps.googleapis.com/maps/api/geocode/json) and to get geolocation in the convenient form (due to the standards of Google Maps). It’s clear it can be only in case the customer specified not only the location country in his account in Facebook.

The registration in Google+ is performed the same way, with the only difference that the callback URL in their system should be fully identical to that specified in the application settings. Thus, all the redirects will get only only to one mapping. It’s convenient to use the returned state parameter for the separation of processes.

@ RequestMapping(value = "/callback/google", method = RequestMethod.GET)
    public class GoogleController extends ExternalController implements Constants {
        @ RequestMapping(value = {"/", ""}, params = "code")
        public ModelAndView googleProxy(@ RequestParam("code") String code, @ RequestParam("state") String state, HttpServletRequest request, HttpServletResponse response) throws Exception { ... }
 
        @ RequestMapping(value = {"/", ""}, params = "error")
        public ModelAndView googleErrorProxy(<hh user=RequestParam>("error") String error, <hh user=RequestParam>("state") String state, HttpServletRequest request) throws Exception { ... }
    }

The other actions, except of the addresses and the returned parameters are identical.

Otherwise the thing is going with the authorization over the OAuth protocol (Twitter and LinkedIn). I’ve gone through the whole chain of authentication but it’s very uncomfortable because of the forming of request with tokens – they should be “glued” packed by base64 in a special way, to add the timing parameters and to make other manipulations. And what’s the most surprising – the sections for social network developers do not reflect these processes. Though this is a standard, so the count is performed due to the standard approach. In any case authorization in this way is implemented “manually” and it is not of the interest for the development of your own application. I suggest to use other free libraries that facilitate this task. For example, there exists a library specifically for Twitter – twitter4j.jar. I used the scribe-java library (http://github.com/fernandezpablo85/scribe-java) which is distributed on the terms of MIT license. The package contains work with Digg API, Facebook API, Flickr API, Freelancer API, Google API, LinkedIn API, Skyrock API, Tumblr API, Twitter API, Vkontakte API, Yahoo API and two dozens of some others.

The registration process for Twitter with the usage of the scribe library will look in the following way. The client request controller for authorization from the registration page:

@ RequestMapping(value = "/registrate/twitter", params = "action", method = RequestMethod.POST)
    public ModelAndView twitterRegistrationJobseeker(HttpServletRequest request) throws Exception {
        OAuthService service = new ServiceBuilder().provider(TwitterApi.class)
            .apiKey(TWITTER_CONSUMER_KEY).apiSecret(TWITTER_CONSUMER_SECRET)
            .callback(TWITTER_URL_CALLBACK_REGISTRATION).build();
        Token requestToken = service.getRequestToken();
        request.getSession().setAttribute("twitter", service);
        request.getSession().setAttribute("request_token", requestToken);
        return new ModelAndView(new RedirectView(service.getAuthorizationUrl(requestToken), true, true, true));
    }

Twitter callback controller:

@ RequestMapping(value = "/callback/twitter", method = RequestMethod.GET)
    public class TwitterController extends ExternalController implements Constants {
        @ RequestMapping(value = "/registration", params = "oauth_verifier")
        public ModelAndView registrationAccessCode(@ RequestParam("oauth_verifier") String verifier, HttpServletRequest request, HttpServletResponse response) throws Exception {
            OAuthService service = (OAuthService) request.getSession().getAttribute("twitter");
            Token accessToken = service.getAccessToken((Token) request.getSession().getAttribute("request_token"), new Verifier(verifier));
            OAuthRequest oauthRequest = new OAuthRequest(Verb.GET, TWITTER_URL_CREDENTIALS);
            service.signRequest(accessToken, oauthRequest);
            Map<String, Json> userInfoResponse = Json.read(oauthRequest.send().getBody()).asJsonMap();
            String twitterId = userInfoResponse.get("id").asString();
            //verifying ...
            Customer customer = new Customer();
            customer.setFirstName((String) request.getSession().getAttribute("pageValueFirstName"));
            //...
            customer = (Customer) userDAO.put(customer);
            TwitterAuthUser user = new TwitterAuthUser();
            user.setAuthority(EnumSet.of(Authority.CUSTOMER));
            user.setIdentificationName(twitterId);
            //...
            user.setOauthToken(accessToken.getToken());
            user.setOauthTokenSecret(accessToken.getSecret());
            user.setType(AuthenticationType.TWITTER);
            user.setUser(customer);
            authenticationDAO.put(user);
            return new ModelAndView(new RedirectView("/registrate.complete", true, true, false));
        }
 
        @ RequestMapping(value = "/registration", params = "denied")
        public ModelAndView registrationError(HttpServletRequest request) {
            //response does not contain the error text
            return new ModelAndView(new RedirectView("/registrate", true, true, false));
        }
        //will signin and signinError
    }

Once again, all is easy and affordable. Registration via LinkedinAPI is performed in a quite the same way.

And the last – registration in a standard way. Standard – hence it’s standard, I won’t show the source code, will only note that we create an object of the SimpleAuthUser type inherited from AuthUser:

    SimpleAuthUser user = new SimpleAuthUser();
        user.setAuthority(EnumSet.of(Authority.NEW_CUSTOMER));
        user.setEnabled(false);
        user.setIdentificationName(email);
        user.setPassword(passwordEncoder.encodePassword(password, email));
        user.setType(AuthenticationType.SIMPLE);
        user.setUser(customer);
        user.setUuid(uuid);
        authenticationDAO.put(user);

For this case the NEW_CUSTOMER authority needed – registered user needs confirmation of registration (standard practice), and that’s why a) it has a different role; b) it’s not allowed for authorization in Spring Security (enabled = false).

Authorization on the website

A simple spring application-context-security.xml:

<security:global-method-security secured-annotations="enabled" jsr250-annotations="enabled" pre-post-annotations="enabled" proxy-target-class="true"/>
 
    <security:http auto-config="true" use-expressions="true">
        <security:intercept-url pattern="/**" access="permitAll"/>
        <security:form-login login-page="/signin"/>
        <security:logout invalidate-session="true" logout-success-url="/" logout-url="/signout"/>
        <security:remember-me services-ref="rememberMeService" key="someRememberMeKey"/>
    </security:http>
 
    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref="authenticationProvider"/>
    </security:authentication-manager>
 
    <bean id="authenticationProvider" class="myproject.security.CustomAuthenticationProvider"/>
 
    <bean id="rememberMeService" class="myproject.security.RememberMeService">
<property name="key" value="someRememberMeKey"/>
<property name="userDetailsService" ref="userDetailsService"/>
    </bean>
 
    <bean id="userDetailsService" class="myproject.security.CustomUserDetailsManager"/>
    <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>

CustomUserDetailsManager.java:

public class CustomUserDetailsManager implements UserDetailsService {
        @ Resource private AuthenticationDAO authenticationDAO;
 
        @ Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            return authenticationDAO.findAuthUser(username);
        }
    }

CustomUserAuthentication.java:

public class CustomUserAuthentication implements Authentication {
        private String name;
        private Object details;
        private UserDetails user;
        private boolean authenticated;
        private Collection<? extends GrantedAuthority> authorities;
 
        public CustomUserAuthentication(UserDetails user, Object details) {
            this.name = user.getUsername();
            this.details = details;
            this.user = user;
            this.authorities = user.getAuthorities();
            authenticated = true;
        }
 
        @ Override
        public String getName() {
            return name;
        }
        @ Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return authorities;
        }
        @ Override
        public Object getCredentials() {
            return user.getPassword();
        }
        @ Override
        public Object getDetails() {
            return details;
        }
        @ Override
        public Object getPrincipal() {
            return user;
        }
        @ Override
        public boolean isAuthenticated() {
            return authenticated;
        }
        @ Override
        public void setAuthenticated(boolean authenticated) throws IllegalArgumentException {
            this.authenticated = authenticated;
        }
    }

CustomAuthenticationProvider.java

(the class is completely clueless, but the interface inheritant AuthenticationProvider should be fed to Spring Security, but the nearest PreAuthenticatedAuthenticationProvider doesn’t fit in meanning):

public class CustomAuthenticationProvider implements AuthenticationProvider {
        @ Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            //тут могут быть доп. проверки
            return authentication;
        }
 
        @ Override
        public boolean supports(Class<?> authentication) {
            return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
        }
 
        public Authentication trust(UserDetails user) {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            Authentication trustedAuthentication = new CustomUserAuthentication(user, authentication.getDetails());
            authentication = authenticate(trustedAuthentication);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            return authentication;
        }
    }

And perhaps the most “narrow” place of security organization is the implementation of the RememberMe mechanism. Basically, everything is already organized so that the work of the RememberMe service fully corresponds to the TokenBasedRememberMeServices implementation, with the only clarification: all the data for automatic client authentication are located in our database, however there can be a situation when the user has already registered on the website and then removed his account on the used social network. And the result is conflict – we authorize the user but in fact he doesn’t exist, i.e. the basic authentication principles by using the third-party services are disrupted. Hence, when the RememberMe mechanism works out we should check the automatically logging client. Such mechanisms are present in every API network provider but we should “intrude” in the work of Spring RememberMe in order to perform the test at the right stage. Unfortunately, it’s not possible to expand some class (the required method is set as final in AbstractRememberMeServices), that’s why you need to completely redefine the class. My way is more cumbersome, I went from the end, abd the trivial human laziness doesn’t permit us to remodel it into the simplier version. I completely redefined the AbstractRememberMeServices class including the TokenBasedRememberMeServices class code, and by adding a couple of strings into the public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) method – after checking the values in the method but before the actual authentication I’ve put a check method call of the client “reality existance”.

Class<? extends ExternalController> controller = externalControllers.get(user.getPassword()); 
    if (controller != null && !controller.newInstance().checkAccount(user)) return null;

And before, I define the static list in the constructor:

private Map<String, Class<? extends ExternalController>> externalControllers;
 
    public CustomRememberMeService() {
        externalControllers = new HashMap<String, Class<? extends ExternalController>>(){{
            put(AuthenticationType.FACEBOOK.name(), FacebookController.class);
            put(AuthenticationType.TWITTER.name(), TwitterController.class);
            put(AuthenticationType.GOOGLE.name(), GoogleController.class);
            put(AuthenticationType.LINKEDIN.name(), LinkedinController.class);
        }};
    }

(this code implementation won’t affect the operation of RememberMe for standard authentication).

And a little easier method implies the replacement of the REMEMBER_ME_FILTER filter to its own where you should put the same code after the mentioned above autoLogin method call, but before the direct authentication. It is less expensive and to code and more logical to understand, however, it requires the intervention of the configuration file. Which way to go – everyone will decide himself, but the second one, in my opinion, is more ideologically “clear”.

Also you should clarify about ExternalController and checkAccount(user) call. All my callback-controllers extend the ExternalController class:

And each controller redefines this only method. For example, in regards to Facebook it’s:

public boolean ?heckAccount(UserDetails user) throws Exception {
        FacebookAuthUser facebookUser = (FacebookAuthUser) user;
        String authRequest = Utils.sendHttpRequest("GET", FACEBOOK_URL_ME, new String[]{"access_token"}, new String[]{facebookUser.getToken()});
        Map<String, Json> tokenInfoResponse = Json.read(authRequest).asJsonMap();
        return tokenInfoResponse.get("error") == null && tokenInfoResponse.get("id").asString().equalsIgnoreCase(facebookUser.getIdentificationName());
    }

and for Twitter:

public boolean checkAccount(UserDetails user) throws Exception {
        TwitterAuthUser twitterUser = (TwitterAuthUser) user;
        OAuthService service = new ServiceBuilder().provider(TwitterApi.class).apiKey(TWITTER_CONSUMER_KEY).apiSecret(TWITTER_CONSUMER_SECRET).build();
        OAuthRequest oauthRequest = new OAuthRequest(Verb.GET, TWITTER_URL_CREDENTIALS);
        service.signRequest(new Token(twitterUser.getOauthToken(), twitterUser.getOauthTokenSecret()), oauthRequest);
        String response = oauthRequest.send().getBody();
        Map<String, Json> info = Json.read(request).asJsonMap();
        return info.get("id").asString().equalsIgnoreCase(twitterUser.getIdentificationName());
    }

and so on.

And the authentication itself (login, sign in) is very similar to the registration. The user visits the page, clicks “Login” and he is being redirected to authentication:

The only thing is that I transfer the “signin” or “autosignin” parameter to the server, depending on the case if the “enter automatically” option is checked. Then all is happenning in a similar scenario with the registration, only the parameter and callback URL are changing and I put away all scope and permission – we need to get only the client ID and hist tokens. After the appropriate checks in the controller methods I suggest you to overwrite tokens into the database. And though, for example, Facebook didn’t change the client token during my tests, and Google+ does this every time. I don’t know how often the “change” happens, that’s why the overwrite is performed after eacb access_token receiving (in fact while each non-automatic authentication of the provider).

And the most important thing – the direct user authentication in Spring Security (definitely after all the checks for the correspondance and verification of rights from API provider), on the example of the Facebook controller:

@ RequestMapping(value = "/signin", params = "code")
    public ModelAndView signInAccessCode(@ RequestParam("code") String code, @ RequestParam("state") String state, HttpServletRequest request, HttpServletResponse response) throws Exception {
        String accessRequest = Utils.sendHttpRequest("GET", FACEBOOK_URL_ACCESS_TOKEN, new String[]{"client_id", "redirect_uri", "client_secret", "code"}, new String[]{FACEBOOK_API_KEY, FACEBOOK_URL_CALLBACK_SIGNIN, FACEBOOK_API_SECRET, code});
        String token = Utils.parseURLQuery(accessRequest).get("access_token");
        Map<String, Json> userInfoResponse = Json.read(Utils.sendHttpRequest("GET", FACEBOOK_URL_ME, new String[]{"access_token"}, new String[]{token})).asJsonMap();
        FacebookAuthUser user = (FacebookAuthUser) authenticationDAO.findAuthUser(userInfoResponse.get("id").asString(), AuthenticationType.FACEBOOK);
        if (user == null) {
            //something went wrong ...
            return new ModelAndView(new RedirectView("/signin", true, true, false));
        } else {
            if (!token.equals(user.getToken())) {
                user.setToken(token);
                user = (FacebookAuthUser) authenticationDAO.put(user);
            }
            Authentication authentication = customAuthenticationProvider.trust(user);
            if (state.equalsIgnoreCase("autosignin")) customRememberMeService.onLoginSuccess(request, response, authentication);
            else customRememberMeService.logout(request, response, authentication); //???????? ???? RememberMe
            return new ModelAndView(new RedirectView("/signin.complete", true, true, false));
        }
    }

Now the client will be automatically logged in when the flag is checked for auto logging in. Hence, if there’s no flag, the logout method call will erase cookies in the RememberMe service (it doesn’t do anything else). By the way, going over the “/logout” link takes the authentication off and cleans cookies automatically. This is overseen by the corresponding line in the Spring Security config above.

Using of the given method can be “atthached” for the standard authentication as well: after going through the checks (finding user in the table, matching password hash and so on) we manually authenticate him:

Authentication authentication = customAuthenticationProvider.trust(user);
    if (autosignin) customRememberMeService.onLoginSuccess(request, response, authentication);
    else customRememberMeService.logout(request, response, authentication);

There’s no difference in usage. The only thing is that while the RememberMe mechanism works out, there’ll be no external checks, in fact, it fully coincides with the work of the TokenBasedRememberMeServices service.

Then using of authentication is similar to using of general roles in Spring Security, with the only difference that you cannot use the @Secured(«CUSTOM_ROLE») annotation, it’s intended for the standard roles (though there’s a mechansim for redefining). But Spring Security has another mechanism – using of the same annotations as @PreAuthorize, @PostFilter: @PreAuthorize(«hasRole(‘ADMINISTRATOR’)»), @PreAuthorize(«hasRole({‘CUSTOMER’, ‘ADMINISTRATOR’})»). You should only specify it in the Spring Security config in the security:global-method-security parameter.

In same way you can use the benefits and opportunities of Spring Security in the view (in JSP). For example:

<%@ taglib prefix="core" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
    ...
    <sec:authorize access="isAuthenticated()">
        <div id="userBox">
            <span>Welcome, <sec:authentication property="principal.user.firstName"/>!</span>
        </div>
    </sec:authorize>

Such constructions allow not to transfer a model from the controller into the view, but to leave the model extract mechanism for the view (it will request for the model to DAO by itself).

Also you can use the jsp-scriplets on jsp-pages (though there’re getting lots of rivals in scriplets using, basically out of the “bean’s – to bean, caesar’s – to caesar” position, developer is programming, coder and/or designer is working on designing, but this is a moot thing, personally me is not the supporter of either one or the other concept – yes, ugly, yes, sometimes very convenient):

<%@ page import="org.springframework.security.core.context.SecurityContextHolder" %>
    <%@ page import="myproject.auth.AuthUser" %>
    <%	Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        AuthUser authUser = null;
        if (!(principal instanceof String)) authUser = (AuthUser) principal; %>
    ...
    <input type="text" <%= authUser == null ? "" : "disabled=\"disabled\"" %> name="your_name" value="<%= authUser == null ? "" : authUser.getUser().getFirstName()%>"/>
    ...
    <% if (authUser == null) { %>
        <div id="recaptcha_widget">
            <div id="recaptchaContainer">
    ...
            </div>
        </div>
    <% } %>

The above code only reflects the opportunities of the security context usage, but it doesn’t pretend for any meaningful logics.

I want to focus on the “narrow” place caused by the lazy dependency between the authentication object and its parameters (object-Principal): without improvements both bunches of code will call Runtime Exception while opening as the user field (calling of the getUser() method) will contain an object with all the fields by default, filled out as null. Using of the OpenSessionInView pattern without the additional extra-loading of the dependent object will not help in this case as there are different HTTP sessions. Therefore it is necessary either to load the dependent object once at boot o, but it is contrary to the approach because of which the lazy connection has been assigned – the object will be loaded and no change in dependent object will update the downloaded one, in this case it is easier to set the EAGER-connection. I’ve resolved this in authenticationDAO by replacing the basically used sessionFactory.getCurrentSession() for opening a new session: SessionFactoryUtils.openSession(sessionFactory). Perhaps this is not the most economical solution in terms of memory but I haven’t questioned myself yet and didn’t dived in depth for the current problem. I consider that by setting the check for validation of the current session you can refuse from the filter and the OpenSessionInView interceptor, in fact by replacing its work.

There’s a bit more text than you need, there are probably exist questionable or even wrong moments but I have tried to reflect the decision of the difficulties encountered during the implementation of the put-up mechanism.

22
Dec

Installing Oracle JDK 7 in Ubuntu 12.04

Posted by eugene as Java

Welcome to all the updated and those who just plans.

As many of you know proprietary Java was compiled from the offcial repositories. In return, the users were suggested to use OpenJDK. However there are serious problems with the stability of work of the last one. But let’s talk in order about all things….

Today, having installed new proxmox 2.1 on the server, I’ve found that the KVM console doesn’t work after the update of my system. I’ve quickly realized that it’s necessary to set up jre and I’ve looked into the terminal and installed openjdk-6-jdk with icedtea-6-plugin for the work of applets.

I restart the browser, go to the web side of proxmox, run the console. That’s all for it, more precisely the dancing just started as here is the incomplete list of problems which I coped with by using as openjdk-6-jdk, so and openjdk-7-jdk:
1) When closing the console window, Firefox falls at all with it.
2) The initialization of the applet with 100% load of CPU at the time the browser is blocked. It continues for quite a long time, which is very enraging.
3) Lots of pop-up proxmox errors.

It’s necessary to confess this is my first experience of working with OpenJDK and probably the last. Finally, I’ve decided to install the propriatery Java and started terrorizing Google, tell everybody how to do this with the minimal loss.

I’ve been almost happy but not for a long time. After that I’ve followed all the steps till the sudo apt-get install point, apt returned me the “Errors were encountered while processing: oracle-java7-installer” alert. And then again I’ve started searching in Google and found how to resolve it. In case someone was caught, I give you the link with cures of this desease.

I was desparate to find a solution in the web, hence I decided to follow the other way – the proved one. By simple manipulations, I’ve managed to make it work, the results pleasantly surprised me. In particular, the problems with the performance and browser crashing have disappeared.

Substance

Hence, we have two variants of that how to do install leaving the system clean. Before you will start, I recommend you to clear the system from OpenJDK:

sudo apt-get purge openjdk*

This command will clear everything what has the relation to all OpenJDK versions.

Method number 1.

Short and quick variant (if you have x86_64), where the .deb package is prepared before by me, put in the network, and you just need to download and install it:
1) Download the package.
2) Run the commands in terminal 4:

# It's necessary to run the transfer (cd command) beforehand into the directory,
# where the download of the .rpm package has been performed
sudo dpkg -i jdk_1.7.004-1_amd64.deb
mkdir -p ~/.mozilla/plugins
ln -s /usr/java/jdk1.7.0_04/jre/lib/amd64/libjavaplugin_jni.so ~/.mozilla/plugins/
ln -s /usr/java/jdk1.7.0_04/jre/lib/amd64/libnpjp2.so ~/.mozilla/plugins/

3) Restart the browser and have fun, also you’ve saved the time.
Of course, if you have 64-bit version of pangolin.

Method number 2, from the start to the end.

1) Go to the Java SE download website and download the (.rpm) package, according to our architecture:
Linux x86 (32-bit)
Linux x64 (64-bit)
2) Install alien, basically this is the package converter which will re-pack the downloaded .rpm packages in the required .deb extension with its own tricks.

sudo apt-get install alien

3) Incite the “alien” to the downloaded rpm.

sudo alien jdk-7u4-linux-x64.rpm --scripts

At this stage, the .deb package will be generated in the same directory.
4) Then install the package, create symlinks and enjoy your life.

sudo dpkg -i jdk_1.7.004-1_amd64.deb
mkdir -p ~/.mozilla/plugins
ln -s /usr/java/jdk1.7.0_04/jre/lib/amd64/libjavaplugin_jni.so ~/.mozilla/plugins/
ln -s /usr/java/jdk1.7.0_04/jre/lib/amd64/libnpjp2.so ~/.mozilla/plugins/

Just will mention that I don’t want to convince that OpenJDK is the blame in everything but the experiments were held on the freshly installed 12.04 and all the problems have been resolved after installing the proprietary version.

21
Dec

Managing tables of the WebSphere Appplication Server scheduler from Java

Posted by eugene as Websphere

Theory

WebSphere is a cool application server with a lot of benefits but it wonders very much how accurately IBM conceals all this from the masses of curious developers. This article highlights the internal control process of the tables control of the internal tasks scheduler directly from the java-application code.

The information about work with the scheduler and its deployment is available in Internet.But once I needed to control the tables integrity directly from applicaiton. And from that moment I had some fun. I haven’t found any information about this process in the internet. Though documentation is for sure available but in scopes of the administration tasks resolution and the examples are given in JACL and Jython languages. In order to move the algorithm into Java it’s clearly not enough as the approaches are a little different.

WebSphere posesses with the internal mechanism of tasks planning. And this is wonderful. For its work you need to deploy the scheduler tables in the database where it will store its tasks. The structure of these tables is represented clearly in the corresponding ddl scripts provided together with WebSphere (AppServer\Scheduler\*.ddl). Moreover, you can even not take care of these tables and to store them in the internal server Derby-base which is provided with the application server of 6.1 version the only package. How is it still possible to control the table scheduler?

I’ve resolved this problem by using the classes of IBM com.ibm.ws.runtime_6.1.0.jar (AppServer\plugins\com.ibm.ws.runtime_6.1.0.jar) library. I haven’t found the documentation about these classes either, that’s why I started my ruthless analysis armored with the help of decompiler.

Practice

Let’s consider the scheduler is deployed and we can refer to it by the JNDI path (for example, java:comp/env/scheduler/ReportScheduler):

 
    Context initialContext = null;
    Scheduler scheduler = null;
 
    try{
        initialContext = new InitialContext();
        scheduler = (Scheduler) initialContext.lookup(SCHEDULER_JNDI_NAME);
    }  catch (NamingException e) {
        throw new SchedulerException("Ошибка инициализации: " + e.getMessage(), e);
    } finally {
        if (initialContext != null) {
            try {
                initialContext.close();
            } catch (NamingException e) {
                logger.log(Level.SEVERE, e.getMessage(), e);
            }
        }
    }

The class which implements the scheduler tables management logics is WASSchedulerCfgHelper which performs the SchedulerConfigHelper interface. The main functions which we need are as follows:

Verification of tables availability

public void verifyTables(SchedulerConfiguration paramSchedulerConfiguration)
throws SchedulerDataStoreException;

Tables creation:

public Boolean createTables(SchedulerConfiguration paramSchedulerConfiguration)
throws SchedulerDataStoreException;

Tables deletion

public Boolean dropTables(SchedulerConfiguration paramSchedulerConfiguration)
throws SchedulerDataStoreException;

Let’s create an instance of the scheduler configuration helper:

SchedulerConfigHelper schedulerHelper = new 
WASSchedulerCfgHelper(SchedulerConfigServiceImpl.getInstance());

As you can see SchedulerConfigHelper applies the obligatory argument in the constructor – SchedulerConfigService. By means of it Helper gets access to the WebSphere resources and to the local variables, but this is an object in the given implementation, frankly speaking, it represents a cap and it does not affect the working process with the tables.

Hence, we receive the parameters of our scheduler – information by means of which helper will be able to find the required scheduler.

SchedulerConfiguration schedulerConfig = scheduler.getSchedulerConfiguration();

And then everything is simple:

if (schedulerHelper.createTables(schedulerConfig)) {
        // Таблицы для шедулера созданы!
        doSomething();
    }

You should take into the account that if the tables have been already created then the method will only leave the corresponding message in the logs and will complete by returning false. The verifyTables method doesn’t return any values and in case of absense of the required tables it throws SchedulerDataStoreException.

By the way you can surely create tables by using the ddl scripts. That’s what I did before but WebSphere API has mechanisms which allow us to abstract from such subtleties as naming of ddl script, path, creating of connection and so on. This is the approach used with the administrative server console.

The used java-decompiler: Java Decompiler

Thank you for attention!