/* * Copyright 2013 The Sculptor Project Team, including the original * author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sculptor.framework.context; import java.security.Principal; import java.util.Collections; import java.util.Random; import java.util.Set; import javax.security.auth.Subject; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import org.sculptor.framework.util.FactoryConfiguration; import org.sculptor.framework.util.FactoryHelper; /** * Factory class to create ServiceContext. * * @author Patrik Nordwall */ public abstract class ServiceContextFactory { private static final int MAX_GENERATED_SESSION_ID = 1000000; public static final String SYSTEM_USER = "system"; public static final String GUEST_USER = "guest"; public static final String UNKNOWN_USER = "unknown"; private static final Random RANDOM_GENERATOR = new Random(System.currentTimeMillis()); private static ServiceContextFactory singletonInstance; private static FactoryConfiguration config = new FactoryConfiguration() { public String getFactoryImplementationClassName() { return "org.sculptor.framework.context.JBossServiceContextFactory"; } }; protected ServiceContextFactory() { } public static void setConfiguration(FactoryConfiguration aConfig) { config = aConfig; } private static ServiceContextFactory getInstance() { if (singletonInstance == null) { singletonInstance = createInstance(); } return singletonInstance; } private static ServiceContextFactory createInstance() { return (ServiceContextFactory) FactoryHelper.newInstanceFromName(config.getFactoryImplementationClassName()); } /** * Convenience method, it requires that the request is a HttpServletRequest. * * @see #createServiceContext(HttpServletRequest) */ public static ServiceContext createServiceContext(ServletRequest request) { if (!(request instanceof HttpServletRequest)) { throw new IllegalArgumentException("Expected HttpServletRequest"); } return createServiceContext((HttpServletRequest) request); } /** * Use this method to create a ServiceContext for a web application. * sessionId is the HttpSession id. applicationId is defined in * <display-name> in web.xml * <p> * The userId and roles are populated from current Subject, which was * created by some Login Module. * <p> * If a ServiceContext instance is already available in thread local * {@link ServiceContextStore} it will be used instead of creating a new * instance. */ public static ServiceContext createServiceContext(HttpServletRequest request) { return getInstance().createServiceContextImpl(request); } protected ServiceContext createServiceContextImpl(HttpServletRequest request) { ServiceContext context = ServiceContextStore.get(); if (context != null) { return context; } String sessionId = request.getSession().getId(); // ServletContextName is defined in <display-name> in web.xml String applicationId = request.getSession().getServletContext().getServletContextName(); String userId = null; Set<String> roles = Collections.emptySet(); Subject caller = activeSubject(); if (caller != null) { userId = userIdFromSubject(caller); roles = rolesFromSubject(caller); } if (userId == null) { // try with this then Principal userPrincipal = request.getUserPrincipal(); if (userPrincipal != null) { userId = userPrincipal.getName(); } } if (userId == null) { // still no user, no login, use guest userId = GUEST_USER; } context = new ServiceContext(userId, sessionId, applicationId, roles); return context; } protected abstract Subject activeSubject(); protected abstract String userIdFromSubject(Subject caller); protected abstract Set<String> rolesFromSubject(Subject caller); /** * Use this method to create a ServiceContext for a system user, e.g. a MDB * for system integration or batch job. * <p> * If a ServiceContext instance is already available in thread local * {@link ServiceContextStore} it will be used instead of creating a new * instance. * * @param applicationId * the id of the external system */ public static ServiceContext createServiceContext(String applicationId) { return getInstance().createServiceContextImpl(applicationId); } protected ServiceContext createServiceContextImpl(String applicationId) { ServiceContext context = ServiceContextStore.get(); if (context != null) { return context; } String sessionId = String.valueOf(RANDOM_GENERATOR.nextInt(MAX_GENERATED_SESSION_ID)); Subject caller = activeSubject(); String userId = null; Set<String> roles = Collections.emptySet(); if (caller != null) { userId = userIdFromSubject(caller); roles = rolesFromSubject(caller); } else { userId = SYSTEM_USER; } context = new ServiceContext(userId, sessionId, applicationId, roles); return context; } }