Blog do projektu Open Source JavaHotel

czwartek, 30 maja 2013

MVP Jython framework and shiro authentication

Introduction
Next step in implementing Shiro authentication for JavaHotel application. Previously I developed an administrator module to add new users, hotels and to set permissions for each user in a particular hotel. Source code is available here.
This module is available in Google App Engine environment. English version and Polish version. User/Password : admin/admin. This module uses standard text based Shiro realm.
[main]
securityManager.sessionManager.sessionValidationSchedulerEnabled = false
[users]
admin=admin
[roles]
securityManager.sessionManager.sessionValidationSchedulerEnabled is disabled because it launches a thread to control session expire time but Google App Engine does not support threads.
Security implementation
After setting hotels and users next step is implemented. User can launch an application for a particular hotel and start activity for this hotel using credential implemented before. For the time being only one functionality is implemented (hotel services).
For accessing a particular hotel URL query hotel parameter is used. Example.
http://testjavahotel.appspot.com/?hotel=hotel
http://testjavahotel.appspot.com/?hotel=hotel1
Application uses another Shiro realm for this purpose.
Shiro realm
[main]
securityManager.sessionManager.sessionValidationSchedulerEnabled = false
hRealm=com.gwthotel.auth.HotelAuthRealm
inject=com.gwthotel.hotel.server.guice.HotelAuthResources
hRealm.iRes=$inject
Test
A simple test scenario can be performed.
  1. Launch http://testjavahotel.appspot.com/?start=admin.xml
  2. Add two hotels : hotel1 and hotel2
  3. Add two users: user1 and user2 (don't forget to set a password for them)
  4. Add user1 access to both hotels and and user2 only to hotel1.
  5. Launch http://testjavahotel.appspot.com/?hotel=hotel1
  6. Make sure that user1 and user2 can logon.
  7. Launch http://testjavahotel.appspot.com/?hotel=hotel2
  8. Make sure that user1 can logon and user2 cannot.
Future
Credentials setting should be modified. The solution that administrator is setting a password is invalid. Another method should be implemented, for instance:  sending a mail containing a temporary password or URL link to set the password for the first time or after resetting the password.

Problem
This application is using two different Shiro realm. During a test I found that I cannot use SecurityUtils.getSubject because after changing the realm a next call to getSubject retrieves users from the previous realm and I was unable to overcome it. The only solution I found was to give up SecurityUtils.getSubject and build Subject directly.
 private static Subject buildSubject() {
        Subject currentUser = new Subject.Builder().buildSubject();
        return currentUser;        
    }

    private Result authenticate(SessionEntry se, String tokenS) {
        SecurityManager securityManager = constructManager(se.getRealm());
        SecurityUtils.setSecurityManager(securityManager);
//        Subject currentUser = SecurityUtils.getSubject();
//        currentUser = new Subject.Builder().buildSubject();
        Subject currentUser = buildSubject();

niedziela, 26 maja 2013

Shiro, customized realm

Introduction
Shiro is very flexible and easy to extend security framework. But creating a custom realm is not  an easy task for the beginners. After some research I created a simple Shiro project to get the gist of the problem.
  1. Authentication using standard text based realm.
  2. The same using customized realm.
  3. The same using injected realm
The source code is available here (in shape of JUnit test case)
JUnit test case
The purpose is to run the same test case but using different realms. Source code.
 private void testShiro(String realM) {
        Factory factory = new IniSecurityManagerFactory(
                realM);
        org.apache.shiro.mgt.SecurityManager securityManager = factory
                .getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        ...........
        test scenario
        ...........


    @Test
    public void test() {
        testShiro("classpath:shiro.ini");
    }

    @Test
    public void test1() {
        testShiro("classpath:custom.ini");
    }

    @Test
    public void test2() {
        testShiro("classpath:inject.ini");
    }

Important: Although test, test1 and test2 are included in one test suite every test should be performed independently. This is because the next test utilize the realm created in the previous test if run inside the same JVM. I did not find a simple way to overcome it.
Standard text based realm
shiro.ini
[users]
root = secret, admin
guest = secret, welcome
Customized realm
custom.ini
[main]
myRealm=com.custom.realm.MyRealm
com.custom.realm.MyRealm
Customized realm with injection
This example is a little more complicated because mini framework has been created. The "framework" contains custom realm and interface.

package com.custom.nextrealm;

import java.util.List;

public interface InjectCredentials {

    String getPerson();
    
    String getPassword();
    
    List getRoles();

}
The user can customize this customized realm by implementing this interface and providing login name, password and list of roles without bothering about all others details. The example of this customization for the purpose of the test :
inject.ini
[main]
myRealm=com.custom.nextrealm.MyRealm
inject=com.custominject.CustomCredentials
myRealm.iCrede=$inject
com.custominject.CustomCredentials

package com.custominject;
import java.util.ArrayList;
import java.util.List;

import com.custom.nextrealm.InjectCredentials;

public class CustomCredentials implements InjectCredentials {

    @Override
    public String getPerson() {
        return "guest";
    }

    @Override
    public String getPassword() {
        return "secret";
    }

    @Override
    public List<String> getRoles() {
        List<String> roles = new ArrayList<String>();
        roles.add("welcome");
        return roles;
    }

}

sobota, 11 maja 2013

Glassfish, EJB, access to

Introduction
I'm planning to prepare a modular version of my JavaHotel application having data access logic hidden in a stateless EJB but creating a simple EJB took me more time that I expected. On one hand it should be simple and other hand (particularly after reading this web page)  it is pretty complicated. So I created a simple Eclipse project showing all important points. Code is available here. The purpose is:

  • Create EJB stateless bean.
  • Access to this bean from standalone Java application to perform JUnit tests.
  • Access to this bean from another Web component.
  • Share common definition without duplicating code.
Shared code
I created Eclipse general (not Java) project being a placeholder for common definition. By virtue of Eclipse "Link source" option this code can be shared between other projects. This project contains above all the interface with business logic implemented by EJB. It is pure  Java interface without any EJB annotation stuff. This share code contains also ServiceLocator class resolving access to EJB.

package com.sample.ejbcalc;

public interface IHelloCalc {

    String getHello();

    int add(int elem1, int elem2);

}

package com.sample.ejblocator;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.sample.ejbcalc.IEJBName;
import com.sample.ejbcalc.IHelloCalc;

public class EJBSampleLocator {
    
    public static IHelloCalc construct() throws NamingException {
        InitialContext ctx = new InitialContext();
        Object remoteObj = new InitialContext().lookup(IEJBName.JNDIRemote);
        IHelloCalc inter = (IHelloCalc) remoteObj;
        return inter;
    }

}

Bean implementation
Source code is available here.

package com.ejbcalc.impl;

import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;

import com.sample.ejbcalc.IEJBName;
import com.sample.ejbcalc.IHelloCalc;

/**
 * Session Bean implementation class CalcImpl
 */
@Stateless
@EJB(name = IEJBName.JNDIRemote, beanInterface = IHelloCalc.class)
@Remote
public class CalcImpl implements IHelloCalc {

    @Override
    public String getHello() {
        return "Hello, I'm your Calculator";
    }

    @Override
    public int add(int elem1, int elem2) {
        return elem1 + elem2;
    }

}
Pay attention to all  annotation stuff.
Standalone JUnit Java application
Source code is available here. Important (Glassfish). It is necessary to add gf-client.jar to classpath. This JUnit uses EJBSampleLocator utility from shared code.

import org.junit.BeforeClass;
import org.junit.Test;

import static org.junit.Assert.*;

import com.sample.ejbcalc.IHelloCalc;
import com.sample.ejblocator.EJBSampleLocator;


public class TestEJB {
    
    private static IHelloCalc i; 

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        i = EJBSampleLocator.construct();
    }

    @Test
    public void test1() {
        assertEquals("Hello, I'm your Calculator",i.getHello());
    }

    @Test
    public void test4() {
        assertEquals(4,i.add(2, 2));
        assertFalse(i.add(2, 2) == 5);
        assertEquals(2,i.add(2, 0));
        assertEquals(2,i.add(0, 2));
        assertEquals(-1,i.add(2, -3));
    }

}
Web component accessing EJB
Last (but not least) Web component. Source code is available here. One servlet reuses common ServiceLocator (like standalone application). But it is also possible to use @EJB annotation and Glassfish  injects EJB directly.

package com.ejbjsp.servlet;

import java.io.IOException;

import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sample.ejbcalc.IHelloCalc;

@WebServlet("/Servlet2")
public class Servlet2 extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @EJB
    private IHelloCalc i;

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {

        response.getOutputStream().println("<h1>
 I'm Servlet 2 </h1&gt;
Bean greetings " + i.getHello() + "</pre&>
");
        response.getOutputStream().println("<br />
<h1>
 Ask Bean. What is 2 + 2 ? Bean's advice: " + i.add(2, 2) + " ! </h1>
");
        response.getOutputStream().flush();
    }

}

czwartek, 9 maja 2013

MVP framework, application and localization

Introduction
Several new features have been added to my MVP framework.
Localization
It is possible to create a fully localized application. Some localized message are framework embedded (for instance messages like: Yes, No, Accept, Resign) and it is possible also to create application specific messages.
More detailed description is available here.
Example of localized application (Google App  Engine).
English (default)
Polish
In both cases U/P is admin/admin
Check list widget utilization
In application available from above a check list widget is used in order to specify permission for the specific user in the specific hotel.
Development/production
The purpose is to develop Web application business logic only in Jython code without recompiling and redeploying the application. It means that during development every request should read fresh copy of jython code and dialog XML format. But of course it should be avoided in production code because it means significant reduction in performance. So development mode is introduced with the following features:
  1. Jython code, XML dialog and message bundles outside java class loader to avoid constantly republishing application to application server (when Eclipse project is open)
  2. No caching, just load resources directly form file system.
  3. Restart Jython with every request
  4. Every request takes a new copy of bundle messages.
Start of Java Hotel development
The application above is the first step in creating Java Hotel application. So far simple administration part is created - allows defining hotels, user and permissions.
Full source code of Java Hotel application created so far is available here. Also not Google App Engine (JPA based) version has been created.
Next step
Authentication to Java Hotel application using realm created in Administrative part described above.

środa, 1 maja 2013

Jython framework and new widget

Introduction
I added new widget to my MVP Jython framework. The purpose is to handle set of checking like that:


It is a matrix of logical values. It can be used like in the example above : to set permissions for a given user in the list of  hotels (or any other objects). The same user can have different permission in every hotel. Lines (rows) are hotels and columns are permissions. Of course - it is a matter of opinion if it were better to have hotels as lines and permissions as columns or opposite. The crux of the matter is to have the 'lines'/'columns' defined programmatically (dynamically) - not statically in the dialog definition.
Implementation
Sample implementation (Google App Engine application) is available here. Click "Check list" button at the bottom. Check/uncheck matrix elements and click "Check". The current values are sent to the Jython code in the background and two values in the upper half are set.
Defining check list in the dialog is very simple - just add checklist tag like in this sample. More than one check list is allowed. Handling values in the backing Jython code is unfortunately more complicated. We have to support three scenarios.
  • Defining lines and columns for the first time.
  • Setting values
  • Getting values.
A pretty complicated data structure is used to accomplish the task. It is described here. A sample Jython code is available here.
Future
  • It is possible to implement a matrix of number (and any other data types) but I can hardly find any use case which can implement it. 
  • Error messages applied directly to the matrix. For instance message like "Checking here is not allowed" in the direct matrix position.
Next steps
I will try to implement the beginning of my new hotel management application. It will be administrative part: defining of hotels, user and permission of user in the particular hotel.  Then implement this solution as a realm for 'Shiro' to implement security for a hotel management (not administrative).

niedziela, 21 kwietnia 2013

New version of JSPWiki in the clouds

Problem
I realized that my humble JSPWiki implementation for Google App Engine is under spam attack. Nasty anonymous user is constantly adding spam message to the main page. I also realized that ACL (Access Control List for pages) does not work in my implementation so I was unable to restrict access to this page.
Solution
After spending some time I enabled ACL for page access. So one can add to the pages stuff like [{ALLOW view SocialCommittee}] and the access is limited. The problem was awkward binding ACL list with the 'WikiPage' class I found in the standard version. But now it seems working, I restricted access to the 'Main' page and although the page was under spam attach all the time the spam message was not added. I also put the spam address to the blacklist (using solution described here) and the battle with spam is over and victorious for the time being.

piątek, 19 kwietnia 2013

Jython framework and security

Introduction
I added security to my Jython/UI MVP framework. Full source code is available here. Current Google App Engine version is available here. Another version of an application (without security enabled) is available here. Also not Google App Engine (tested with Tomcat and Glassfish) has been created. Current documentation is available here.
Authentication and Shiro
Authentication is implemented using Apache Shiro. Only standalone API is used now. I found this framework very useful - it fulfills what is needed and is very simple at the same time. In sample application the simplest authentication realm is used but the doors is open to implement more sophisticated authentication environment.
Authentication and two modes
It is controlled by Authenticate property in app.properties file (example).
  • Authenticate=Y : Restricted mode, access to all pages requires authentication token. Cannot get access without being authenticated.
  • Authenticate=N (default) : Not restricted mode. Access for not authenticated users to some pages is possible.
Login enforcement
Starting pages (specified by 'start' http query argument) enforcing login page are specified in app.properties file. Parameter 'Login' should contain list of starting page requiring login window. All starting pages not specified there are accessible without authentication (only if not restricted mode is enabled).
Authentication token
After successful login authentication token is returned to the client. From now on all access to the server  should be performed by using this token. Any password (with except to the login page) is stored at the client side just making all stuff more secure.
Authentication token and server
Unfortunately, this solution does not come cheap. It is related to the fact that the purpose is to have server side stateless, just ready to run in cloud environment. So the solution cannot rely on Shiro session  because next request can be executed in a fresh instance of JVM just having previous session invalidated.  The problem is described here in Shiro documentation. So both user name and password should be stored at the server side after user authentication ready to authenticate again against the Shiro session. Credentials are stored in a cache and also in backing persistent storage in case of being removed from cache. Implementation of cache and persistent storage is different for Google App Engine and not Google App Engine implementation. The simple algorithm for caching credentials is common.

public class SecuritySessionStore implements ISecuritySessionCache {

    private final ISecuritySessionMemCache iMemCache;
    private final ISecuritySessionPersistent iPersistent;

    private static final Logger log = Logger
            .getLogger(SecuritySessionStore.class.getName());

    @Inject
    public SecuritySessionStore(ISecuritySessionMemCache iMemCache,
            ISecuritySessionPersistent iPersistent) {
        this.iMemCache = iMemCache;
        this.iPersistent = iPersistent;
    }

    @Override
    public Object get(String key) throws InvalidClassException {
        Object val = iMemCache.get(key);
        if (val != null)
            return val;
        val = iPersistent.get(key);
        if (val == null)
            return null;
        // add value to cache again
        log.log(Level.FINE, LogMess.getMessN(ILogMess.PUTINCACHEAGAIN, key));
        iMemCache.put(key, val);
        return val;
    }

    @Override
    public void put(String key, Object o) {
        iMemCache.put(key, o);
        iPersistent.put(key, o);
    }

    @Override
    public void remove(String key) {
        iMemCache.remove(key);
        iPersistent.remove(key);
    }

}
By virtue of Guice the proper implementation of ISecuritySessionMemCache and ISecuritySessionPersitent is injected.
Authorization and Jexl
Three types of authorization is used. User, role and permission. Sometimes authorization rule can be complicated (for instance: give access to the user identified by name or the user having the role). So I decided to user Jexl for creating boolean expression evaluating to True (is authorized) or False (is not authorized).
To create an expression three methods are defined: sec.u (current user is the user authorized), sec.r (current user has the role) and sec.p (current user has permission). Using this three methods even complicated expression can be created.
Example:
Only 'darkhelmet' user is authorized and all user belonging to 'shwartz' role. Jexl expression: sec.u('dearkhelmer) or sec.r('schwartz')
Two types of authorization
Static way, restrict access in the xml dialog definition. Two attributes : 'readonly' and 'hidden' can be enriched with security expression. If expression evaluates to True for current user then attribute is enabled otherwise is disabled. This attributes can be attached to fields in the form, columns in the list and buttons. If 'hidden' is enabled then simple the element is not visible and not accessible. If 'readonly' is enabled then the element is visible but cannot be modified or clicked (in case of button).
Dynamic way, from 'jython' code. Authorization can be also enforced in 'jython' code at the server side just allowing to apply any logic to authorization rule. Examples:
from guice import ServiceInjector

def dialogaction(action,var) :
  iSec = ServiceInjector.constructSecurity()
  token = var["SECURITY_TOKEN"]
  ok = iSec.isAuthorized(token,"sec.u('darkhelmet')")
  var["OK"] = ok
Tests
 Both types of tests: GUI testing using Boa/Selenium framework (test cases) and Junit test cases have been created for security enhancement.
Future, next steps
It is the first version of security enhancement. Further development:

  • 'Hidden'. Current version simple applies 'hidden' attribute to HTML element. It is not rendered but is visible in HTML code. Future version will contain 'superhidden' attribute. Such a field will not be included in the HTML code.
  • Current version stored password at the server side in plain text. It should be encoded in real production code.
  • More attributes covered with authorization.