JaasBean.java 9.43 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.*;

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

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

import fi.codecrew.moya.AuthenticationResult;
import fi.codecrew.moya.MoyaRealmBeanRemote;
import fi.codecrew.moya.enums.BortalApplication;
import fi.codecrew.moya.enums.apps.IAppPermission;
import fi.codecrew.moya.enums.apps.SpecialPermission;
import fi.codecrew.moya.enums.apps.UserPermission;
import fi.codecrew.moya.facade.ApiApplicationFacade;
import fi.codecrew.moya.facade.ApiApplicationInstanceFacade;
import fi.codecrew.moya.facade.EventUserFacade;
import fi.codecrew.moya.facade.UserFacade;
import fi.codecrew.moya.model.ApiApplication;
import fi.codecrew.moya.model.ApiApplicationInstance;
import fi.codecrew.moya.model.ApplicationPermission;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.LanEvent;
import fi.codecrew.moya.model.LanEventProperty;
import fi.codecrew.moya.model.LanEventPropertyKey;
import fi.codecrew.moya.model.Role;
import fi.codecrew.moya.model.User;
import fi.codecrew.moya.utilities.PasswordFunctions;
import fi.codecrew.moya.utilities.moyamessage.MoyaEventType;

/**
 * Session Bean implementation class SessionHandlerBean
 */
@Stateless(mappedName = MoyaRealmBeanRemote.REMOTE_BEAN_NAME)
public class JaasBean implements MoyaRealmBeanRemote {

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

	@EJB
	private UserFacade userfacade;

	@EJB
	private EventUserFacade eventUserFacade;

	@EJB
	private UserBean userbean;
	@EJB
	private PermissionBeanLocal permbean;
	@EJB
	private EventBeanLocal eventbean;

	@EJB
	private RestBean restbean;
	@EJB
	private ApiApplicationFacade appfacade;
	@EJB
	private ApiApplicationInstanceFacade appInstanceFacade;
	@EJB
	private EventBean eventorgbean;

	@EJB
	private LoggingBeanLocal secubean;

	public EventUser tryLogin(String username, String password) {
		// 	username = username.trim().toLowerCase();

		EventUser eventUser = eventUserFacade.findByLogin(username);
		logger.info("Found eventuser '{}' with username '{}'", eventUser, username);

		User user = null;
		// Might not have EventUser
		if (eventUser == null) {
			user = userfacade.findByLogin(username);
		} else {
			user = eventUser.getUser();
		}

		
		logger.info("User '{}' with '{}' ", user, username);

		// If there is no eventuser found, try to create one.
		if (user != null) {
			logger.info("TryLogin user not null: {}, login {}", user, user.getLogin());
			if (user.isAnonymous()) {
				logger.info("logging in as anonymous!!!");
			} else if (!user.checkPassword(password)) {

				secubean.sendMessage(MoyaEventType.LOGIN_FAILED, eventUser, "Login failed: wrong password for username: ", username);
				eventUser = null;
				user = null;
			}
			LanEventProperty inviteonly = eventbean.getProperty(LanEventPropertyKey.INVITE_ONLY_EVENT);

			boolean createEventuser = true;
			if (inviteonly != null && inviteonly.isBooleanValue()) {
				createEventuser = false;
			}
			if (createEventuser && user != null && eventUser == null)
			{
				LanEvent event = eventbean.getCurrentEvent();
				eventUser = new EventUser(user, event, null);
				// eventUser.setCreator(eventUser);
				eventUserFacade.create(eventUser);
				eventUserFacade.flush();
				eventUser.setCreator(eventUser);
			}

			// jos logitetaan anomuumi, niin uuden tapahtuman luominen hajoaa jännästi.
			if (user != null && !user.isAnonymous())
				secubean.sendMessage(MoyaEventType.LOGIN_SUCCESSFULL, eventUser, "User logged in with username: '", username, "' eventuser: ", eventUser);
		} else {
			secubean.sendMessage(MoyaEventType.LOGIN_FAILED, eventUserFacade.findByLogin(User.ANONYMOUS_LOGINNAME), "Login failed: Username not found: ", username);
		}

		return eventUser;
	}

	// public static void foo()
	// {
	// if (user != null) {
	// LanEvent event = eventbean.getCurrentEvent();
	// eventUser = new EventUser(user, event, null);
	// // eventUser.setCreator(eventUser);
	// eventUserFacade.create(eventUser);
	// eventUserFacade.flush();
	// eventUser.setCreator(eventUser);
	// }
	// }

	public static enum UserType
	{
		USER, REST
	}

	@Override
	public AuthenticationResult authUsername(String username, String password) {

		AuthenticationResult ret = new AuthenticationResult();
		ret.setUsertype(UserType.USER.name());

		if ((username == null || username.isEmpty()) && password.startsWith("rest:")) {
			ret.setUsertype(UserType.REST.name());
			ret.setUsername(restAuth(password));

		} else {
			EventUser retUser = tryLogin(username, password);
			if (retUser != null) {
				ret.setUsername(retUser.getLogin());
			}
		}
		return ret;
	}

	@Override
	public boolean authenticate(String username, String password) {
		return (tryLogin(username, password) != null);
	}

	private String restAuth(String restauth) {
		String[] authsplit = restauth.split(":", 6);
		logger.info("Trying to auth with rest {}", (Object) authsplit);
		if (authsplit.length != 6 || !authsplit[0].equals("rest")) {
			return null;
		}

		return authenticateApp(authsplit[5], authsplit[1], authsplit[2], authsplit[3], authsplit[4]);
	}

	@Override
	public Enumeration<String> getGroupNames(String user, String usertype) {
		EventUser usr = eventUserFacade.findByLogin(user.toLowerCase().trim());
		HashSet<String> roleset = new HashSet<String>();
		roleset.add(UserPermission.ANYUSER.getFullName());

		if (usr == null) {

			usr = permbean.getAnonEventUser();
			roleset.add(SpecialPermission.ANONYMOUS.name());
		}

		if (usertype != null) {
			try {
				switch (UserType.valueOf(usertype))
				{
				case REST:
					roleset.add(SpecialPermission.REST.name());
					break;
				case USER:
					break;
				default:
					throw new RuntimeException("Unknown user type: " + usertype);
				}
			} catch (Exception t) {
				logger.warn("UserType authentication " + usertype, t);
			}
		}

		if (!usr.getUser().isAnonymous()) {
			// all logged in users should be able to logout :)
			roleset.add(UserPermission.LOGOUT.name());
			roleset.add(SpecialPermission.USER.name());
		}
		// TODO: EI NÄIN!!!!! Superadmin ei saa kaikkia oikkia!!

		if (usr.getUser().isSuperadmin()) {
			for (BortalApplication app : BortalApplication.values()) {
				for (IAppPermission perm : app.getPermissions()) {
					roleset.add(perm.getFullName());
				}
			}
			roleset.add(SpecialPermission.SUPERADMIN.name());
		} else {

			Set<Role> usrroles = userbean.localFindUsersRoles(usr);
			for (Role role : usrroles) {
				for (ApplicationPermission apperm : role.getPermissions()) {
					roleset.add(apperm.getPermission().getFullName());
				}
			}
			LanEvent event = eventbean.getCurrentEvent();

			if (event != null && !usr.getUser().isAnonymous() && event.getDefaultRole() != null) {
				for (ApplicationPermission apperm : event.getDefaultRole().getPermissions()) {
					roleset.add(apperm.getPermission().getFullName());
				}
			}
		}

		Vector<String> retvect = new Vector<String>();
		retvect.addAll(roleset);
		logger.debug("group names for user {}: {}", user, retvect);

		return retvect.elements();
	}

	@Override
	public Enumeration<String> getGroupNames(String username) {
		return getGroupNames(username, null);
	}

	public String authenticateApp(String pathInfo, String appId, String userId, String appStamp, String mac) {

		logger.info("Authenticat app with pathinfo {}, appid {}, userid {}, appstamp {}, mac {}",
				new Object[] { pathInfo, appId, userId, appStamp, mac }
				);
		if (mac == null) {
			logger.warn("Rest auth failed: Mac is null");
			return null;
		}
		ApiApplication app = appfacade.findByAppid(appId);
		if (app == null) {
			logger.warn("Rest auth failed: Application not found for appid {}", appId);
			return null;
		}
		ApiApplicationInstance apiInstance = appInstanceFacade.findInstance(app, userId);
		if (apiInstance == null) {
			logger.warn("Rest auth failed; because appInstance not found for app{} and user {}", app, userId);
			return null;
		}
		if (!app.isEnabled() || !apiInstance.isEnabled()) {
			logger.warn("Rest auth failed: app or api-instance is disabled: app {}, apiInstance: {}", app, apiInstance);
			return null;
		}

		String ret = null;
		String macSource = PasswordFunctions.mkSeparatedString("+", pathInfo, appId, userId, appStamp, apiInstance.getSecretKey());
		String macHash = PasswordFunctions.calculateSha1(macSource);
		logger.info("Calculated hash {}, comparing to {}", macHash, mac);
		if (mac.equalsIgnoreCase(macHash))
		{
			switch (app.getAuthtype()) {
			case ORGAUTH:
				ret = User.ANONYMOUS_LOGINNAME;
				break;
			case USERKEY:
				if (apiInstance.getEventuser() != null) {
					ret = apiInstance.getEventuser().getUser().getLogin();
				}
				break;
			default:
				throw new RuntimeException("Unknown application authtype!");
			}
		} else {
			logger.warn("Rest auth failed: Calculated hash does not match received mac: Calculated {}, received {}", macHash, mac);
		}

		return ret;
	}
}