001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.security.auth.login;
023:
024: import java.io.File;
025: import java.io.IOException;
026: import java.io.InputStream;
027: import java.io.InputStreamReader;
028: import java.net.MalformedURLException;
029: import java.net.URL;
030: import java.security.AccessController;
031: import java.security.PrivilegedAction;
032: import java.util.ArrayList;
033: import javax.security.auth.AuthPermission;
034: import javax.security.auth.login.AppConfigurationEntry;
035: import javax.security.auth.login.Configuration;
036:
037: import org.jboss.logging.Logger;
038: import org.jboss.security.SecurityConstants;
039: import org.jboss.security.auth.spi.UsersObjectModelFactory;
040: import org.jboss.xb.binding.JBossXBException;
041: import org.jboss.xb.binding.Unmarshaller;
042: import org.jboss.xb.binding.UnmarshallerFactory;
043:
044: /** An concrete implementation of the javax.security.auth.login.Configuration
045: class that parses an xml configuration of the form:
046:
047: <policy>
048: <application-policy name = "test-domain">
049: <authentication>
050: <login-module code = "org.jboss.security.plugins.samples.IdentityLoginModule"
051: flag = "required">
052: <module-option name = "principal">starksm</module-option>
053: </login-module>
054: </authentication>
055: </application-policy>
056: </policy>
057:
058: @see javax.security.auth.login.Configuration
059:
060: @author Scott.Stark@jboss.org
061: @version $Revision: 57203 $
062: */
063: public class XMLLoginConfigImpl extends Configuration {
064:
065: private static final AuthPermission REFRESH_PERM = new AuthPermission(
066: "refreshLoginConfiguration");
067: private static Logger log = Logger
068: .getLogger(XMLLoginConfigImpl.class);
069: /** A mapping of application name to AppConfigurationEntry[]
070: protected Map appConfigs = Collections.synchronizedMap(new HashMap());
071: */
072: PolicyConfig appConfigs = new PolicyConfig();
073: /** The URL to the XML or Sun login configuration */
074: protected URL loginConfigURL;
075: /** The inherited configuration we delegate to */
076: protected Configuration parentConfig;
077: /** A flag indicating if XML configs should be validated */
078: private boolean validateDTD = true;
079:
080: // --- Begin Configuration method overrrides
081: public void refresh() {
082: SecurityManager sm = System.getSecurityManager();
083: if (sm != null)
084: sm.checkPermission(REFRESH_PERM);
085: if (log.isTraceEnabled())
086: log.trace("Begin refresh");
087: appConfigs.clear();
088: loadConfig();
089: if (log.isTraceEnabled())
090: log.trace("End refresh");
091: }
092:
093: public AppConfigurationEntry[] getAppConfigurationEntry(
094: String appName) {
095: if (log.isTraceEnabled())
096: log.trace("Begin getAppConfigurationEntry(" + appName
097: + "), size=" + appConfigs.size());
098: // If the config has not been loaded try to do so
099: if (loginConfigURL == null) {
100: loadConfig();
101: }
102:
103: AppConfigurationEntry[] entry = null;
104: AuthenticationInfo authInfo = (AuthenticationInfo) appConfigs
105: .get(appName);
106: if (authInfo == null) {
107: if (log.isTraceEnabled())
108: log
109: .trace("getAppConfigurationEntry("
110: + appName
111: + "), no entry in appConfigs, tyring parentCont: "
112: + parentConfig);
113: if (parentConfig != null)
114: entry = parentConfig.getAppConfigurationEntry(appName);
115: if (entry == null) {
116: if (log.isTraceEnabled())
117: log
118: .trace("getAppConfigurationEntry("
119: + appName
120: + "), no entry in parentConfig, trying: "
121: + SecurityConstants.DEFAULT_APPLICATION_POLICY);
122: }
123: authInfo = (AuthenticationInfo) appConfigs
124: .get(SecurityConstants.DEFAULT_APPLICATION_POLICY);
125: }
126:
127: if (authInfo != null) {
128: if (log.isTraceEnabled())
129: log.trace("End getAppConfigurationEntry(" + appName
130: + "), authInfo=" + authInfo);
131: // Make a copy of the authInfo object
132: final AuthenticationInfo theAuthInfo = authInfo;
133: PrivilegedAction action = new PrivilegedAction() {
134: public Object run() {
135: return theAuthInfo.copyAppConfigurationEntry();
136: }
137: };
138: entry = (AppConfigurationEntry[]) AccessController
139: .doPrivileged(action);
140: } else {
141: if (log.isTraceEnabled())
142: log.trace("End getAppConfigurationEntry(" + appName
143: + "), failed to find entry");
144: }
145:
146: return entry;
147: }
148:
149: // --- End Configuration method overrrides
150:
151: /** Set the URL of the XML login configuration file that should
152: be loaded by this mbean on startup.
153: */
154: public URL getConfigURL() {
155: return loginConfigURL;
156: }
157:
158: /** Set the URL of the XML login configuration file that should
159: be loaded by this mbean on startup.
160: */
161: public void setConfigURL(URL loginConfigURL) {
162: this .loginConfigURL = loginConfigURL;
163: }
164:
165: public void setConfigResource(String resourceName)
166: throws IOException {
167: ClassLoader tcl = Thread.currentThread()
168: .getContextClassLoader();
169: loginConfigURL = tcl.getResource(resourceName);
170: if (loginConfigURL == null)
171: throw new IOException("Failed to find resource: "
172: + resourceName);
173: }
174:
175: public void setParentConfig(Configuration parentConfig) {
176: this .parentConfig = parentConfig;
177: }
178:
179: /** Get whether the login config xml document is validated againsts its DTD
180: */
181: public boolean getValidateDTD() {
182: return this .validateDTD;
183: }
184:
185: /** Set whether the login config xml document is validated againsts its DTD
186: */
187: public void setValidateDTD(boolean flag) {
188: this .validateDTD = flag;
189: }
190:
191: /** Add an application configuration
192: */
193: public void addAppConfig(String appName,
194: AppConfigurationEntry[] entries) {
195: SecurityManager sm = System.getSecurityManager();
196: if (sm != null)
197: sm.checkPermission(REFRESH_PERM);
198: AuthenticationInfo authInfo = new AuthenticationInfo(appName);
199: authInfo.setAppConfigurationEntry(entries);
200: if (log.isTraceEnabled())
201: log.trace("addAppConfig(" + appName + "), authInfo="
202: + authInfo);
203: appConfigs.add(authInfo);
204: }
205:
206: public void removeAppConfig(String appName) {
207: SecurityManager sm = System.getSecurityManager();
208: if (sm != null)
209: sm.checkPermission(REFRESH_PERM);
210: if (log.isTraceEnabled())
211: log.trace("removeAppConfig, appName=" + appName);
212: appConfigs.remove(appName);
213: }
214:
215: public void clear() {
216:
217: }
218:
219: /** Called to try to load the config from the java.security.auth.login.config
220: * property value when there is no loginConfigURL.
221: */
222: public void loadConfig() {
223: // Try to load the java.security.auth.login.config property
224: String loginConfig = System
225: .getProperty("java.security.auth.login.config");
226: if (loginConfig == null)
227: loginConfig = "login-config.xml";
228:
229: // If there is no loginConfigURL build it from the loginConfig
230: if (loginConfigURL == null) {
231: try {
232: // Try as a URL
233: loginConfigURL = new URL(loginConfig);
234: } catch (MalformedURLException e) {
235: // Try as a resource
236: try {
237: setConfigResource(loginConfig);
238: } catch (IOException ignore) {
239: // Try as a file
240: File configFile = new File(loginConfig);
241: try {
242: setConfigURL(configFile.toURL());
243: } catch (MalformedURLException ignore2) {
244: }
245: }
246: }
247: }
248:
249: if (loginConfigURL == null) {
250: log.warn("Failed to find config: " + loginConfig);
251: return;
252: }
253:
254: if (log.isTraceEnabled())
255: log.trace("Begin loadConfig, loginConfigURL="
256: + loginConfigURL);
257: // Try to load the config if found
258: try {
259: loadConfig(loginConfigURL);
260: if (log.isTraceEnabled())
261: log.trace("End loadConfig, loginConfigURL="
262: + loginConfigURL);
263: } catch (Exception e) {
264: log.warn("End loadConfig, failed to load config: "
265: + loginConfigURL, e);
266: }
267: }
268:
269: protected String[] loadConfig(URL config) throws Exception {
270: SecurityManager sm = System.getSecurityManager();
271: if (sm != null)
272: sm.checkPermission(REFRESH_PERM);
273:
274: ArrayList configNames = new ArrayList();
275: log.debug("Try loading config as XML, url=" + config);
276: try {
277: loadXMLConfig(config, configNames);
278: } catch (Throwable e) {
279: log.debug("Failed to load config as XML", e);
280: log
281: .debug("Try loading config as Sun format, url="
282: + config);
283: loadSunConfig(config, configNames);
284: }
285: String[] names = new String[configNames.size()];
286: configNames.toArray(names);
287: return names;
288: }
289:
290: private void loadSunConfig(URL sunConfig, ArrayList configNames)
291: throws Exception {
292: InputStream is = sunConfig.openStream();
293: if (is == null)
294: throw new IOException("InputStream is null for: "
295: + sunConfig);
296:
297: InputStreamReader configFile = new InputStreamReader(is);
298: boolean trace = log.isTraceEnabled();
299: SunConfigParser.doParse(configFile, this , trace);
300: }
301:
302: private void loadXMLConfig(URL loginConfigURL, ArrayList configNames)
303: throws IOException, JBossXBException {
304: LoginConfigObjectModelFactory lcomf = new LoginConfigObjectModelFactory();
305: UsersObjectModelFactory uomf = new UsersObjectModelFactory();
306:
307: InputStreamReader xmlReader = loadURL(loginConfigURL);
308: Unmarshaller unmarshaller = UnmarshallerFactory.newInstance()
309: .newUnmarshaller();
310: unmarshaller.mapFactoryToNamespace(uomf,
311: "http://www.jboss.org/j2ee/schemas/XMLLoginModule");
312: Object root = null;
313: PolicyConfig config = (PolicyConfig) unmarshaller.unmarshal(
314: xmlReader, lcomf, root);
315: configNames.addAll(config.getConfigNames());
316: appConfigs.copy(config);
317: }
318:
319: private InputStreamReader loadURL(URL configURL) throws IOException {
320: InputStream is = configURL.openStream();
321: if (is == null)
322: throw new IOException(
323: "Failed to obtain InputStream from url: "
324: + configURL);
325: InputStreamReader xmlReader = new InputStreamReader(is);
326: return xmlReader;
327: }
328:
329: }
|