001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.geronimo.security.deployment;
017:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.HashMap;
021: import java.util.HashSet;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.Set;
025:
026: import javax.xml.namespace.QName;
027:
028: import org.apache.geronimo.common.DeploymentException;
029: import org.apache.geronimo.deployment.DeploymentContext;
030: import org.apache.geronimo.deployment.service.SingleGBeanBuilder;
031: import org.apache.geronimo.deployment.service.XmlAttributeBuilder;
032: import org.apache.geronimo.deployment.service.XmlReferenceBuilder;
033: import org.apache.geronimo.deployment.xbeans.PatternType;
034: import org.apache.geronimo.deployment.xbeans.XmlAttributeType;
035: import org.apache.geronimo.gbean.AbstractName;
036: import org.apache.geronimo.gbean.AbstractNameQuery;
037: import org.apache.geronimo.gbean.GBeanData;
038: import org.apache.geronimo.gbean.GBeanInfo;
039: import org.apache.geronimo.gbean.GBeanInfoBuilder;
040: import org.apache.geronimo.gbean.GReferenceInfo;
041: import org.apache.geronimo.gbean.ReferenceMap;
042: import org.apache.geronimo.gbean.ReferencePatterns;
043: import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
044: import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
045: import org.apache.geronimo.kernel.Kernel;
046: import org.apache.geronimo.kernel.Naming;
047: import org.apache.geronimo.security.jaas.JaasLoginModuleUse;
048: import org.apache.geronimo.security.jaas.LoginModuleControlFlag;
049: import org.apache.geronimo.security.jaas.LoginModuleControlFlagEditor;
050: import org.apache.geronimo.security.jaas.LoginModuleGBean;
051: import org.apache.geronimo.xbeans.geronimo.loginconfig.GerAbstractLoginModuleType;
052: import org.apache.geronimo.xbeans.geronimo.loginconfig.GerLoginConfigDocument;
053: import org.apache.geronimo.xbeans.geronimo.loginconfig.GerLoginConfigType;
054: import org.apache.geronimo.xbeans.geronimo.loginconfig.GerLoginModuleRefType;
055: import org.apache.geronimo.xbeans.geronimo.loginconfig.GerLoginModuleType;
056: import org.apache.geronimo.xbeans.geronimo.loginconfig.GerOptionType;
057: import org.apache.xmlbeans.XmlCursor;
058: import org.apache.xmlbeans.XmlObject;
059: import org.apache.xmlbeans.XmlOptions;
060:
061: /**
062: * @version $Rev: 555771 $ $Date: 2007-07-12 14:22:48 -0700 (Thu, 12 Jul 2007) $
063: */
064: public class LoginConfigBuilder implements XmlReferenceBuilder {
065: public static final String LOGIN_CONFIG_NAMESPACE = GerLoginConfigDocument.type
066: .getDocumentElementName().getNamespaceURI();
067: private static final QName LOGIN_MODULE_QNAME = new QName(
068: LOGIN_CONFIG_NAMESPACE, "login-module");
069: private static final QName SERVER_SIDE_QNAME = new QName(null,
070: "server-side");
071:
072: private final Naming naming;
073: private final Map xmlAttributeBuilderMap;
074:
075: public LoginConfigBuilder(Kernel kernel,
076: Collection xmlAttributeBuilderMap) {
077: this (kernel.getNaming(), xmlAttributeBuilderMap);
078: }
079:
080: public LoginConfigBuilder(Naming naming,
081: Collection xmlAttributeBuilders) {
082: this .naming = naming;
083: if (xmlAttributeBuilders != null) {
084: ReferenceMap.Key key = new ReferenceMap.Key() {
085:
086: public Object getKey(Object object) {
087: return ((XmlAttributeBuilder) object)
088: .getNamespace();
089: }
090: };
091: xmlAttributeBuilderMap = new ReferenceMap(
092: xmlAttributeBuilders, new HashMap(), key);
093: } else {
094: xmlAttributeBuilderMap = new HashMap();
095: }
096: }
097:
098: public String getNamespace() {
099: return LOGIN_CONFIG_NAMESPACE;
100: }
101:
102: public ReferencePatterns getReferences(XmlObject xmlObject,
103: DeploymentContext context, AbstractName parentName,
104: ClassLoader classLoader) throws DeploymentException {
105: List<GBeanData> uses = new ArrayList<GBeanData>();
106: GerLoginConfigType loginConfig = (GerLoginConfigType) xmlObject
107: .copy().changeType(GerLoginConfigType.type);
108: XmlCursor xmlCursor = loginConfig.newCursor();
109: xmlCursor.push();
110: try {
111: //munge xml
112: if (xmlCursor.toChild(LOGIN_MODULE_QNAME)) {
113: do {
114: xmlCursor.removeAttribute(SERVER_SIDE_QNAME);
115: } while (xmlCursor.toNextSibling(LOGIN_MODULE_QNAME));
116: }
117: xmlCursor.pop();
118: //validate
119: XmlOptions xmlOptions = new XmlOptions();
120: xmlOptions.setLoadLineNumbers();
121: Collection errors = new ArrayList();
122: xmlOptions.setErrorListener(errors);
123: if (!loginConfig.validate(xmlOptions)) {
124: throw new DeploymentException(
125: "Invalid login configuration:\n" + errors
126: + "\nDescriptor: "
127: + loginConfig.toString());
128: }
129: //find the login modules
130: Set<String> loginModuleNames = new HashSet<String>();
131: boolean atStart = true;
132: while ((atStart && xmlCursor.toFirstChild())
133: || (!atStart && xmlCursor.toNextSibling())) {
134: atStart = false;
135: XmlObject child = xmlCursor.getObject();
136: GerAbstractLoginModuleType abstractLoginModule = (GerAbstractLoginModuleType) child;
137: String controlFlag = abstractLoginModule
138: .getControlFlag().toString();
139: boolean wrapPrincipals = (abstractLoginModule
140: .isSetWrapPrincipals() && abstractLoginModule
141: .getWrapPrincipals());
142: ReferencePatterns loginModuleReferencePatterns;
143: String name;
144: if (abstractLoginModule instanceof GerLoginModuleRefType) {
145: GerLoginModuleRefType loginModuleRef = (GerLoginModuleRefType) abstractLoginModule;
146: PatternType patternType = loginModuleRef
147: .getPattern();
148: AbstractNameQuery loginModuleNameQuery = SingleGBeanBuilder
149: .buildAbstractNameQuery(patternType,
150: USE_REFERENCE_INFO);
151: loginModuleReferencePatterns = new ReferencePatterns(
152: loginModuleNameQuery);
153: name = (String) loginModuleNameQuery.getName().get(
154: "name");
155: if (name == null) {
156: throw new DeploymentException(
157: "You must specify the name of the login module in the login module ref "
158: + patternType);
159: }
160: //TODO configid reinstate this check for duplicate domain names
161: // try
162: // {
163: // String loginDomain = (String) context.getAttribute(loginModuleName, "loginDomainName");
164: // if (!loginModuleNames.add(loginDomain))
165: // {
166: // throw new DeploymentException("Security realm contains two login domains called '" + loginDomain + "'");
167: // }
168: // }
169: // catch (DeploymentException e)
170: // {
171: // throw e;
172: // }
173: // catch (Exception e)
174: // {
175: // throw new DeploymentException("Unable to create reference to login module " + name, e);
176: // }
177: } else if (abstractLoginModule instanceof GerLoginModuleType) {
178: //create the LoginModuleGBean also
179: AbstractName loginModuleName;
180:
181: GerLoginModuleType loginModule = (GerLoginModuleType) abstractLoginModule;
182: name = trim(loginModule.getLoginDomainName());
183: if (!loginModuleNames.add(name)) {
184: throw new DeploymentException(
185: "Security realm contains two login domains called '"
186: + name + "'");
187: }
188: String className = trim(loginModule
189: .getLoginModuleClass());
190: Map<String, Object> options = new HashMap<String, Object>();
191: GerOptionType[] optionArray = loginModule
192: .getOptionArray();
193: for (GerOptionType gerOptionType : optionArray) {
194: String key = gerOptionType.getName();
195: String value = trim(gerOptionType
196: .getStringValue());
197: options.put(key, value);
198: }
199: XmlAttributeType[] xmlOptionArray = loginModule
200: .getXmlOptionArray();
201: if (xmlOptionArray != null) {
202: for (XmlAttributeType xmlOptionType : xmlOptionArray) {
203: String key = xmlOptionType.getName().trim();
204: XmlObject[] anys = xmlOptionType
205: .selectChildren(XmlAttributeType.type
206: .qnameSetForWildcardElements());
207: if (anys.length != 1) {
208: throw new DeploymentException(
209: "Unexpected count of xs:any elements in xml-attribute "
210: + anys.length
211: + " qnameset: "
212: + XmlAttributeType.type
213: .qnameSetForWildcardElements());
214: }
215: String namespace = xmlObject.getDomNode()
216: .getNamespaceURI();
217: XmlAttributeBuilder builder = (XmlAttributeBuilder) xmlAttributeBuilderMap
218: .get(namespace);
219: if (builder == null) {
220: throw new DeploymentException(
221: "No attribute builder deployed for namespace: "
222: + namespace);
223: }
224: Object value = builder.getValue(xmlObject,
225: null, classLoader);
226: options.put(key, value);
227: }
228: }
229: loginModuleName = naming.createChildName(
230: parentName, name, NameFactory.LOGIN_MODULE);
231: loginModuleReferencePatterns = new ReferencePatterns(
232: loginModuleName);
233: GBeanData loginModuleGBeanData = new GBeanData(
234: loginModuleName,
235: LoginModuleGBean.GBEAN_INFO);
236: loginModuleGBeanData.setAttribute(
237: "loginDomainName", name);
238: loginModuleGBeanData.setAttribute(
239: "loginModuleClass", className);
240: loginModuleGBeanData.setAttribute("options",
241: options);
242: loginModuleGBeanData.setAttribute("wrapPrincipals",
243: wrapPrincipals);
244:
245: context.addGBean(loginModuleGBeanData);
246: } else {
247: throw new DeploymentException(
248: "Unknown abstract login module type: "
249: + abstractLoginModule.getClass());
250: }
251: AbstractName this Name;
252: this Name = naming.createChildName(parentName, name,
253: "LoginModuleUse");
254: GBeanData loginModuleUseGBeanData = new GBeanData(
255: this Name, JaasLoginModuleUse.GBEAN_INFO);
256: loginModuleUseGBeanData.setAttribute("controlFlag",
257: getControlFlag(controlFlag));
258: loginModuleUseGBeanData.setReferencePatterns(
259: "LoginModule", loginModuleReferencePatterns);
260: uses.add(loginModuleUseGBeanData);
261: }
262: for (int i = uses.size() - 1; i >= 0; i--) {
263: GBeanData data = uses.get(i);
264: if (i > 0) {
265: uses.get(i - 1).setReferencePattern("Next",
266: data.getAbstractName());
267: }
268: context.addGBean(data);
269: }
270: } catch (GBeanAlreadyExistsException e) {
271: throw new DeploymentException(e);
272: } finally {
273: xmlCursor.dispose();
274: }
275: return uses.size() == 0 ? null : new ReferencePatterns(uses
276: .get(0).getAbstractName());
277: }
278:
279: private LoginModuleControlFlag getControlFlag(String controlFlag) {
280: LoginModuleControlFlagEditor editor = new LoginModuleControlFlagEditor();
281: editor.setAsText(controlFlag);
282: return (LoginModuleControlFlag) editor.getValue();
283: }
284:
285: private String trim(String string) {
286: return string == null ? null : string.trim();
287: }
288:
289: public static final GBeanInfo GBEAN_INFO;
290:
291: private static final GReferenceInfo USE_REFERENCE_INFO;
292:
293: static {
294: GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(
295: LoginConfigBuilder.class, "XmlReferenceBuilder");
296: infoBuilder.addAttribute("kernel", Kernel.class, false, false);
297: infoBuilder.addReference("xmlAttributeBuilders",
298: XmlAttributeBuilder.class, "XmlAttributeBuilder");
299: infoBuilder.setConstructor(new String[] { "kernel",
300: "xmlAttributeBuilders" });
301: infoBuilder.addInterface(XmlReferenceBuilder.class);
302: GBEAN_INFO = infoBuilder.getBeanInfo();
303:
304: Set<GReferenceInfo> referenceInfos = JaasLoginModuleUse.GBEAN_INFO
305: .getReferences();
306: GReferenceInfo found = null;
307: for (GReferenceInfo testReferenceInfo : referenceInfos) {
308: String testRefName = testReferenceInfo.getName();
309: if (testRefName.equals("LoginModule")) {
310: found = testReferenceInfo;
311: break;
312: }
313: }
314: if (found == null) {
315: throw new RuntimeException(
316: "Someone changed the gbeaninfo on JaasLoginModuleUse");
317: }
318: USE_REFERENCE_INFO = found;
319:
320: }
321:
322: public static GBeanInfo getGBeanInfo() {
323: return GBEAN_INFO;
324: }
325: }
|