net.databinder.auth.hib.AuthDataApplication.java Source code

Java tutorial

Introduction

Here is the source code for net.databinder.auth.hib.AuthDataApplication.java

Source

/*
 * Databinder: a simple bridge from Wicket to Hibernate
 * Copyright (C) 2006  Nathan Hamblen nathan@technically.us
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package net.databinder.auth.hib;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.servlet.http.HttpServletRequest;

import net.databinder.auth.AuthApplication;
import net.databinder.auth.AuthSession;
import net.databinder.auth.components.hib.DataSignInPage;
import net.databinder.auth.data.DataUser;
import net.databinder.hib.DataApplication;
import net.databinder.hib.Databinder;

import org.apache.wicket.Component;
import org.apache.wicket.RestartResponseAtInterceptPageException;
import org.apache.wicket.Session;
import org.apache.wicket.authorization.IUnauthorizedComponentInstantiationListener;
import org.apache.wicket.authorization.UnauthorizedInstantiationException;
import org.apache.wicket.authroles.authorization.strategies.role.IRoleCheckingStrategy;
import org.apache.wicket.authroles.authorization.strategies.role.RoleAuthorizationStrategy;
import org.apache.wicket.authroles.authorization.strategies.role.Roles;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Response;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.http.WebRequest;
import org.apache.wicket.util.crypt.Base64;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.criterion.Restrictions;

/**
 * Adds basic authentication functionality to DataApplication. This class is a derivative
 * of Wicket's AuthenticatedWebApplication, brought into the DataApplication hierarchy
 * and including light user specifications in DataUser. You are encouraged to override
 * getUserClass() to implement your own user entity, possibly by extending UserBase.
 * It is also possible to use Databinder authentication without extending this base class 
 * by implementing IAuthSettings.
 * <p>Text appearing in authentication components can be overriden for any language, using
 * resource keys listed in their documentation. Except as otherwise noted, these resources
 * can be housed in the application class's properties file, so that subclasses of  the pages
 * and panels are not necessarily required.
 * @see AuthApplication
 * @see DataUser
 * @author Nathan Hamblen
 */
public abstract class AuthDataApplication extends DataApplication
        implements IUnauthorizedComponentInstantiationListener, IRoleCheckingStrategy, AuthApplication {

    /**
     * Internal initialization. Client applications should not normally override
     * or call this method.
     */
    @Override
    protected void internalInit() {
        super.internalInit();
        authInit();
    }

    /**
     * Sets Wicket's security strategy for role authorization and appoints this 
     * object as the unauthorized instatiation listener. Called automatically on start-up.
     */
    protected void authInit() {
        getSecuritySettings().setAuthorizationStrategy(new RoleAuthorizationStrategy(this));
        getSecuritySettings().setUnauthorizedComponentInstantiationListener(this);
    }

    /**
     * @return new AuthDataSession
     * @see AuthDataSession
     */
    @Override
    public Session newSession(Request request, Response response) {
        return new AuthDataSession(request);
    }

    /**
     * Adds to the configuration whatever DataUser class is defined.
     */
    @Override
    protected void configureHibernate(AnnotationConfiguration config) {
        super.configureHibernate(config);
        config.addAnnotatedClass(getUserClass());
    }

    /**
     * Sends to sign in page if not signed in, otherwise throws UnauthorizedInstantiationException.
     */
    public void onUnauthorizedInstantiation(Component component) {
        if (((AuthSession) Session.get()).isSignedIn()) {
            throw new UnauthorizedInstantiationException(component.getClass());
        } else {
            throw new RestartResponseAtInterceptPageException(getSignInPageClass());
        }
    }

    /**
     * Passes query on to the DataUser object if signed in.
     */
    public final boolean hasAnyRole(Roles roles) {
        DataUser user = ((AuthSession) Session.get()).getUser();
        if (user != null)
            for (String role : roles)
                if (user.hasRole(role))
                    return true;
        return false;
    }

    /**
     * Return user object by matching against a "username" property. Override
     * if you have a differently named property.
     * @return DataUser for the given username. 
     */
    public DataUser getUser(String username) {
        return (DataUser) Databinder.getHibernateSession().createCriteria(getUserClass())
                .add(Restrictions.eq("username", username)).uniqueResult();
    }

    /**
     * Override if you need to customize the sign-in page.
     * @return page to sign in users
     */
    public Class<? extends WebPage> getSignInPageClass() {
        return DataSignInPage.class;
    }

    /**
     * @return app-salted MessageDigest.  
     */
    public MessageDigest getDigest() {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA");
            digest.update(getSalt());
            return digest;
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("SHA Hash algorithm not found.", e);
        }
    }

    /**
     * Get the restricted token for a user, using IP addresses as location parameter. This implementation
     * combines the "X-Forwarded-For" header with the remote address value so that unique
     * values result with and without proxying. (The forwarded header is not trusted on its own
     * because it can be most easily spoofed.)
     * @param user source of token
     * @return restricted token
     */
    public String getToken(DataUser user) {

        ServletWebRequest request = ((ServletWebRequest) RequestCycle.get().getRequest());
        HttpServletRequest req = request.getContainerRequest();
        String fwd = req.getHeader("X-Forwarded-For");
        if (fwd == null)
            fwd = "nil";
        MessageDigest digest = getDigest();
        user.getPassword().update(digest);
        digest.update((fwd + "-" + req.getRemoteAddr()).getBytes());
        byte[] hash = digest.digest(user.getUsername().getBytes());
        return new String(Base64.encodeBase64(hash));
    }
}