com.ikanow.infinit.e.api.utils.RESTTools.java Source code

Java tutorial

Introduction

Here is the source code for com.ikanow.infinit.e.api.utils.RESTTools.java

Source

/*******************************************************************************
 * Copyright 2012, The Infinit.e Open Source Project.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 * 
 * This program 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package com.ikanow.infinit.e.api.utils;

import java.net.InetAddress;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.util.Date;
import java.util.Map;

import org.apache.log4j.Logger;
import org.bson.types.ObjectId;
import org.restlet.data.Form;
import org.restlet.resource.ServerResource;

import com.ikanow.infinit.e.api.authentication.PasswordEncryption;
import com.ikanow.infinit.e.data_model.store.DbManager;
import com.ikanow.infinit.e.data_model.store.social.authentication.AuthenticationPojo;
import com.ikanow.infinit.e.data_model.store.social.cookies.CookiePojo;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;

public class RESTTools {
    private static final Logger logger = Logger.getLogger(RESTTools.class);
    private static final long COOKIE_TIMEOUT = 900000; //1000ms * 60s * 15m
    public static final String AUTH_TOKEN_NAME = "inf_token";

    public static ObjectId generateRandomId() {
        SecureRandom randomBytes = new SecureRandom();
        byte bytes[] = new byte[12];
        randomBytes.nextBytes(bytes);
        return new ObjectId(bytes);
    }

    public static String decodeRESTPostParam(String name, Map<String, String> attributes) {
        String toDecode = (String) attributes.get(name);
        if (null == toDecode) {
            return null;
        } else {
            return decodeURL(toDecode);
        }
    }

    public static String getEncodedRESTParam(String name, Map<String, Object> attributes) {
        return (String) attributes.get(name);
    }

    public static String decodeRESTParam(String name, Map<String, Object> attributes) {
        String toDecode = (String) attributes.get(name);
        if (null == toDecode) {
            return null;
        } else {
            return decodeURL(toDecode);
        }
    }

    public static String decodeURL(String toDecode) {
        String decodedString = "";
        try {
            decodedString = URLDecoder.decode(toDecode, "UTF-8");
        } catch (Exception e) {
            logger.error("Line: [" + e.getStackTrace()[2].getLineNumber() + "] " + e.getMessage());
            e.printStackTrace();
        }
        return decodedString;
    }

    /**
     * Creates a new session for a user, adding
     * an entry to our cookie table (maps cookieid
     * to userid) and starts the clock
     * 
     * @param username
     * @param bMulti if true lets you login from many sources
     * @param bOverride if false will fail if already logged in
     * @return
     */
    public static ObjectId createSession(ObjectId userid, boolean bMulti, boolean bOverride) {

        try {
            DBCollection cookieColl = DbManager.getSocial().getCookies();

            if (!bMulti) { // Otherwise allow multiple cookies for this user
                //remove any old cookie for this user
                BasicDBObject dbQuery = new BasicDBObject();
                dbQuery.put("profileId", userid);
                dbQuery.put("apiKey", new BasicDBObject(DbManager.exists_, false));
                DBCursor dbc = cookieColl.find(dbQuery);
                if (bOverride) {
                    while (dbc.hasNext()) {
                        cookieColl.remove(dbc.next());
                    }
                } //TESTED
                else if (dbc.length() > 0) {
                    return null;
                } //TESTED
            }
            //Find user
            //create a new entry
            CookiePojo cp = new CookiePojo();
            ObjectId randomObjectId = generateRandomId();

            cp.set_id(randomObjectId);
            cp.setCookieId(randomObjectId);
            cp.setLastActivity(new Date());
            cp.setProfileId(userid);
            cp.setStartDate(new Date());
            cookieColl.insert(cp.toDb());
            //return cookieid
            return cp.getCookieId();
        } catch (Exception e) {
            logger.error("Line: [" + e.getStackTrace()[2].getLineNumber() + "] " + e.getMessage());
            e.printStackTrace();
        }

        return null;
    }

    /**
     * Users the cookieid that is saved to the browser to look up a the
     * currently logged in users id
     * 
     * Checks if cookie has been active in last 15 minutes otherwise denies 
     * request and removes cookie.
     * 
     * If cookie is active, updates last access time.
     * 
     * @param cookieIdStr
     * @return Returns userid associated with this cookie
     */
    public static String cookieLookup(String cookieIdStr) {
        if ((null == cookieIdStr) || cookieIdStr.equalsIgnoreCase("null") || cookieIdStr.isEmpty())
            return null;
        try {
            //remove any old cookie for this user
            CookiePojo cookieQuery = new CookiePojo();
            if (cookieIdStr.startsWith("api:")) {
                cookieQuery.setApiKey(cookieIdStr.substring(4));
            } else {
                cookieQuery.set_id(new ObjectId(cookieIdStr));
            }
            BasicDBObject cookieQueryDbo = (BasicDBObject) cookieQuery.toDb();
            DBObject dbo = DbManager.getSocial().getCookies().findOne(cookieQueryDbo);
            ObjectId userid = null;
            if (dbo != null) {
                CookiePojo cp = CookiePojo.fromDb(dbo, CookiePojo.class);
                if (null != cp.getApiKey()) {
                    userid = cp.getProfileId();
                    // (no activity/timeout)
                } //TESTED
                else {
                    PropertiesManager props = new PropertiesManager();
                    Long timeout_s = props.getApiTimeoutSeconds();
                    long nTimeout_ms = (null == timeout_s) ? COOKIE_TIMEOUT : 1000L * timeout_s;
                    if ((new Date().getTime() - cp.getLastActivity().getTime()) < nTimeout_ms) {
                        //less than 15min, update activity time
                        cp.setLastActivity(new Date());
                        DbManager.getSocial().getCookies().update(cookieQueryDbo, cp.toDb());
                        userid = cp.getProfileId();
                    } else {
                        //to late, drop cookie
                        DbManager.getSocial().getCookies().remove(dbo);
                    }
                } //TESTED
            }
            if (null == userid) {
                return null;
            }
            return userid.toString();
        } catch (Exception e) {
            logger.error("Line: [" + e.getStackTrace()[2].getLineNumber() + "] " + e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    // By default, admin must be enabled
    public static boolean adminLookup(String personIdStr) {
        return adminLookup(personIdStr, true);
    }

    public static boolean adminLookup(String personIdStr, boolean mustBeEnabled) {
        if (null == personIdStr)
            return false;
        try {
            AuthenticationPojo authQuery = new AuthenticationPojo();
            authQuery.setProfileId(new ObjectId(personIdStr));
            BasicDBObject dbo = (BasicDBObject) DbManager.getSocial().getAuthentication().findOne(authQuery.toDb());
            if (null != dbo) {
                AuthenticationPojo ap = AuthenticationPojo.fromDb(dbo, AuthenticationPojo.class);
                return adminCheck(ap, mustBeEnabled);
            }
            return false;
        } catch (Exception e) {
            logger.error("Line: [" + e.getStackTrace()[2].getLineNumber() + "] " + e.getMessage(), e);
            e.printStackTrace();
        } catch (Error e) {
            logger.error("isAdminError", e);
            e.printStackTrace();
        }
        return false;
    }

    // Utility function for the two types of authentication   
    public static boolean adminCheck(AuthenticationPojo ap, boolean mustBeEnabled) {
        if (null != ap.getAccountType()) {
            if (ap.getAccountType().equalsIgnoreCase("admin")) {
                return true;
            } else if (ap.getAccountType().equalsIgnoreCase("admin-enabled")) {
                if (!mustBeEnabled) {
                    return true;
                } else if (null != ap.getLastSudo()) {
                    if ((ap.getLastSudo().getTime() + 10 * 60 * 1000) > new Date().getTime()) {
                        // (ie admin rights last 10 minutes)
                        return true;
                    }
                }
            }
        } //TESTED      
        return false;
    }

    public static void logRequest(ServerResource requestHandle) {
        Form headers = (Form) requestHandle.getResponseAttributes().get("org.restlet.http.headers");
        if (null == headers) {
            headers = new Form();
            requestHandle.getResponseAttributes().put("org.restlet.http.headers", headers);
        }
        headers.add("X-infinit.e.log", "1");
    }//TESTED

    static public boolean mustComeFromAuthority(PropertiesManager properties, String ipAddress, String cookie,
            String admuser, String admpass) {
        boolean allowedToRegisterUpdate = false;
        if (properties.isSaasDeployment()) //if saas, must come from trusted ip
        {
            String[] trustedDnsNames = properties.getSaasTrustedDns().split("\\s*,\\s*");
            for (String dns : trustedDnsNames) {
                InetAddress authIpAddress;
                try {
                    authIpAddress = InetAddress.getByName(dns);
                } catch (UnknownHostException e) {
                    return false;
                }
                if (ipAddress.equals(authIpAddress.getHostAddress())) {
                    allowedToRegisterUpdate = true;
                    break;
                }
            } // (end loop over allowed DNS)
        }
        if (!allowedToRegisterUpdate && (null != cookie)) //if not saas, must be an admin
        {
            String cookieLookup = cookieLookup(cookie); //get cookie to check admin
            allowedToRegisterUpdate = adminLookup(cookieLookup);
        }

        if (!allowedToRegisterUpdate && (null != admuser) && (null != admpass)) {
            // ie IP address / cookie doesn't match, system is also allowed to use admin user/pass:

            // 1. Check user/pass is valid:

            // 2. Check user is admin
            try {
                BasicDBObject query = new BasicDBObject();
                query.put("username", admuser);
                if (44 != admpass.length()) { // hash if in the clear
                    admpass = PasswordEncryption.encrypt(admpass);
                }
                query.put("password", admpass);

                AuthenticationPojo ap = AuthenticationPojo
                        .fromDb(DbManager.getSocial().getAuthentication().findOne(query), AuthenticationPojo.class);
                if (null != ap) {
                    allowedToRegisterUpdate = adminCheck(ap, true);
                } //TESTED (admin, admin-enabled, non-admin)
            } catch (Exception e) {
                // Do nothing
            }
        }
        return allowedToRegisterUpdate;

    }//TESTED (just moved code across from PersonInterface)

    private final static String ATTRIBUTE_VAR_PREFIX = "$";

    /**
     * Looks in attributes for attr_name.  If nothing is there returns null.
     * If result is a String that starts with $var_name will look in queryOptions
     * for var_name and return that instead, otherwise null.
     * 
     * 
     * @param attr_name
     * @param attributes
     * @param queryOptions
     * @return
     */
    public static String getUrlAttribute(String attr_name, Map<String, Object> attributes,
            Map<String, String> queryOptions) {
        String attr = RESTTools.getEncodedRESTParam(attr_name, attributes);
        if (attr != null) {
            if (attr.startsWith(ATTRIBUTE_VAR_PREFIX)) {
                //special case to grab from queryOptions instead of attribute
                String attr_var_name = attr.substring(ATTRIBUTE_VAR_PREFIX.length());
                return (String) queryOptions.get(attr_var_name); // (ie or null
            } else {
                //was just in attribute
                return decodeURL(attr);
            }
        }
        return null;
    }

}