001/******************************************************************************* 002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 *******************************************************************************/ 014package org.nuxeo.runtime.api.login; 015 016import java.util.concurrent.atomic.AtomicInteger; 017 018import javax.security.auth.login.AppConfigurationEntry; 019import javax.security.auth.login.Configuration; 020 021import org.apache.commons.logging.LogFactory; 022 023public class LoginConfiguration extends Configuration { 024 025 public static final LoginConfiguration INSTANCE = new LoginConfiguration(); 026 027 protected final AtomicInteger counter = new AtomicInteger(0); 028 029 public interface Provider { 030 031 public AppConfigurationEntry[] getAppConfigurationEntry(String name); 032 033 } 034 035 protected final InheritableThreadLocal<Provider> holder = new InheritableThreadLocal<Provider>() { 036 @Override 037 protected Provider initialValue() { 038 return context.provider; 039 }; 040 }; 041 042 @Override 043 public AppConfigurationEntry[] getAppConfigurationEntry(String name) { 044 AppConfigurationEntry[] appConfigurationEntry = holder.get().getAppConfigurationEntry(name); 045 if (appConfigurationEntry == null) { 046 appConfigurationEntry = context.parent.getAppConfigurationEntry(name); 047 } 048 return appConfigurationEntry; 049 050 } 051 052 @Override 053 public void refresh() { 054 context.parent.refresh(); 055 } 056 057 protected class InstallContext { 058 protected final Configuration parent = Configuration.getConfiguration(); 059 060 protected final Provider provider; 061 062 protected final Thread thread = Thread.currentThread(); 063 064 protected final Throwable stacktrace = new Throwable(); 065 066 protected InstallContext(Provider provider) { 067 this.provider = provider; 068 } 069 070 @Override 071 public String toString() { 072 return "Login Installation Context [parent=" + parent + ", thread=" + thread + "]"; 073 } 074 075 } 076 077 protected InstallContext context; 078 079 public void install(Provider provider) { 080 holder.set(provider); 081 int count = counter.incrementAndGet(); 082 if (count == 1) { 083 context = new InstallContext(provider); 084 Configuration.setConfiguration(this); 085 LogFactory.getLog(LoginConfiguration.class).trace("installed login configuration", context.stacktrace); 086 } 087 } 088 089 public void uninstall() { 090 holder.remove(); 091 int count = counter.decrementAndGet(); 092 if (count == 0) { 093 LogFactory.getLog(LoginConfiguration.class).trace("uninstalled login configuration " + context.thread, 094 context.stacktrace); 095 Configuration.setConfiguration(context.parent); 096 context = null; 097 } 098 } 099 100 /** 101 * @since 5.9.5 102 */ 103 public void cleanupThisThread() { 104 holder.remove(); 105 } 106 107}