RestBean.java 3.6 KB
/*
 * Copyright Codecrew Ry
 * 
 * All rights reserved.
 * 
 * This license applies to any software containing a notice placed by the 
 * copyright holder. Such software is herein referred to as the Software. 
 * This license covers modification, distribution and use of the Software. 
 * 
 * Any distribution and use in source and binary forms, with or without 
 * modification is not permitted without explicit written permission from the 
 * copyright owner. 
 * 
 * A non-exclusive royalty-free right is granted to the copyright owner of the 
 * Software to use, modify and distribute all modifications to the Software in 
 * future versions of the Software. 
 * 
 */
package fi.codecrew.moya.beans;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.SessionContext;
import javax.ejb.Singleton;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fi.codecrew.moya.facade.ApiApplicationFacade;
import fi.codecrew.moya.facade.ApiApplicationInstanceFacade;
import fi.codecrew.moya.utilities.PasswordFunctions;

/**
 * Session Bean implementation class RestAuthBean
 */
@Singleton
@LocalBean
public class RestBean implements RestBeanLocal {

	/**
	 * Default constructor.
	 */
	public RestBean() {
		// TODO Auto-generated constructor stub
	}

	@Resource
	private TimerService ts;

	@Resource
	private SessionContext context;

	private static final Logger logger = LoggerFactory.getLogger(RestBean.class);

	@PostConstruct
	public void initialize() {
		ts.createTimer(60 * 1000, 60 * 1000, null);
	}

	@EJB
	private ApiApplicationFacade appfacade;
	@EJB
	private ApiApplicationInstanceFacade apiInstanceFacade;

	@Timeout
	public void timeoutNonces(Timer timer) {
		int count = 0;
		long now = System.currentTimeMillis();
		synchronized (userRestAuths) {
			for (Map<String, Long> ua : userRestAuths.values()) {
				for (Entry<String, Long> no : ua.entrySet()) {
					if (no != null && now > no.getValue()) {
						ua.remove(no.getKey());
						++count;
					}
				}
			}
		}
		logger.info("Timeouted {} nonces", count);

	}

	// Username -> Nonce -> expiration
	private ConcurrentHashMap<String, ConcurrentHashMap<String, Long>> userRestAuths = new ConcurrentHashMap<>();

	@Override
	public String getLoggedinUserRestNonce() {
		String username = context.getCallerPrincipal().getName();
		if (username == null) {
			return null;
		}
		ConcurrentHashMap<String, Long> userAuthMap = userRestAuths.get(username);
		if (userAuthMap == null) {
			userAuthMap = userRestAuths.putIfAbsent(username, new ConcurrentHashMap<>());
		}

		Random random = new Random();

		int charcount = 20 + random.nextInt(10);
		String nonce = null;

		do {
			nonce = PasswordFunctions.generateRandomString(charcount, PasswordFunctions.ALL_CHARS);
		} while (userAuthMap.containsKey(nonce));
		userAuthMap.put(nonce, System.currentTimeMillis() + 120 * 1000); // Timeout in 60 seconds.
		return nonce;
	}

	@Override
	public boolean validateUserNonce(String nonce) {
		String username = context.getCallerPrincipal().getName();
		boolean ret = false;

		// Validation is successfull if user exists, nonce exists and timeout has not passed. 
		if (username != null && userRestAuths.containsKey(username)) {
			Long time = userRestAuths.get(username).remove(nonce);
			ret = time != null && time > System.currentTimeMillis();
		}
		return ret;
	}

}