001 /**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements. See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.geronimo.security.deployment;
019
020 import java.util.ArrayList;
021 import java.util.Collection;
022 import java.util.HashSet;
023 import java.util.Iterator;
024 import java.util.List;
025 import java.util.Properties;
026 import java.util.Set;
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.XmlReferenceBuilder;
032 import org.apache.geronimo.deployment.xbeans.PatternType;
033 import org.apache.geronimo.gbean.AbstractName;
034 import org.apache.geronimo.gbean.AbstractNameQuery;
035 import org.apache.geronimo.gbean.GBeanData;
036 import org.apache.geronimo.gbean.GBeanInfo;
037 import org.apache.geronimo.gbean.GBeanInfoBuilder;
038 import org.apache.geronimo.gbean.GReferenceInfo;
039 import org.apache.geronimo.gbean.ReferencePatterns;
040 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
041 import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
042 import org.apache.geronimo.kernel.Naming;
043 import org.apache.geronimo.kernel.Kernel;
044 import org.apache.geronimo.security.jaas.JaasLoginModuleUse;
045 import org.apache.geronimo.security.jaas.LoginModuleGBean;
046 import org.apache.geronimo.xbeans.geronimo.loginconfig.GerAbstractLoginModuleType;
047 import org.apache.geronimo.xbeans.geronimo.loginconfig.GerLoginConfigType;
048 import org.apache.geronimo.xbeans.geronimo.loginconfig.GerLoginModuleRefType;
049 import org.apache.geronimo.xbeans.geronimo.loginconfig.GerLoginModuleType;
050 import org.apache.geronimo.xbeans.geronimo.loginconfig.GerOptionType;
051 import org.apache.geronimo.xbeans.geronimo.loginconfig.GerLoginConfigDocument;
052 import org.apache.xmlbeans.XmlCursor;
053 import org.apache.xmlbeans.XmlObject;
054 import org.apache.xmlbeans.XmlOptions;
055
056
057 /**
058 * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
059 */
060 public class LoginConfigBuilder implements XmlReferenceBuilder {
061 public static final String LOGIN_CONFIG_NAMESPACE = GerLoginConfigDocument.type.getDocumentElementName().getNamespaceURI();
062
063 private final Naming naming;
064
065 public LoginConfigBuilder(Kernel kernel) {
066 this.naming = kernel.getNaming();
067 }
068
069 public LoginConfigBuilder(Naming naming) {
070 this.naming = naming;
071 }
072
073 public String getNamespace() {
074 return LOGIN_CONFIG_NAMESPACE;
075 }
076
077 public ReferencePatterns getReferences(XmlObject xmlObject, DeploymentContext context, AbstractName parentName, ClassLoader classLoader) throws DeploymentException {
078 GerLoginConfigType loginConfig = (GerLoginConfigType) xmlObject.copy().changeType(GerLoginConfigType.type);
079 XmlOptions xmlOptions = new XmlOptions();
080 xmlOptions.setLoadLineNumbers();
081 Collection errors = new ArrayList();
082 xmlOptions.setErrorListener(errors);
083 if (!loginConfig.validate(xmlOptions)) {
084 throw new DeploymentException("Invalid login configuration:\n" + errors + "\nDescriptor: " + loginConfig.toString());
085 }
086 XmlCursor xmlCursor = loginConfig.newCursor();
087 List uses = new ArrayList();
088 Set loginModuleNames = new HashSet();
089 try {
090 boolean atStart = true;
091 while ((atStart && xmlCursor.toFirstChild()) || (!atStart && xmlCursor.toNextSibling())) {
092 atStart = false;
093 XmlObject child = xmlCursor.getObject();
094 GerAbstractLoginModuleType abstractLoginModule = (GerAbstractLoginModuleType) child;
095 String controlFlag = abstractLoginModule.getControlFlag().toString();
096 boolean wrapPrincipals = (abstractLoginModule.isSetWrapPrincipals() && abstractLoginModule.getWrapPrincipals());
097 ReferencePatterns loginModuleReferencePatterns;
098 String name;
099 if (abstractLoginModule instanceof GerLoginModuleRefType) {
100 GerLoginModuleRefType loginModuleRef = (GerLoginModuleRefType) abstractLoginModule;
101 PatternType patternType = loginModuleRef.getPattern();
102 AbstractNameQuery loginModuleNameQuery = SingleGBeanBuilder.buildAbstractNameQuery(patternType, USE_REFERENCE_INFO);
103 loginModuleReferencePatterns = new ReferencePatterns(loginModuleNameQuery);
104 name = (String) loginModuleNameQuery.getName().get("name");
105 if (name == null) {
106 throw new DeploymentException("You must specify the name of the login module in the login module ref " + patternType);
107 }
108 //TODO configid reinstate this check for duplicate domain names
109 // try
110 // {
111 // String loginDomain = (String) context.getAttribute(loginModuleName, "loginDomainName");
112 // if (!loginModuleNames.add(loginDomain))
113 // {
114 // throw new DeploymentException("Security realm contains two login domains called '" + loginDomain + "'");
115 // }
116 // }
117 // catch (DeploymentException e)
118 // {
119 // throw e;
120 // }
121 // catch (Exception e)
122 // {
123 // throw new DeploymentException("Unable to create reference to login module " + name, e);
124 // }
125 } else if (abstractLoginModule instanceof GerLoginModuleType) {
126 //create the LoginModuleGBean also
127 AbstractName loginModuleName;
128
129 GerLoginModuleType loginModule = (GerLoginModuleType) abstractLoginModule;
130 name = trim(loginModule.getLoginDomainName());
131 if (!loginModuleNames.add(name)) {
132 throw new DeploymentException("Security realm contains two login domains called '" + name + "'");
133 }
134 String className = trim(loginModule.getLoginModuleClass());
135 boolean serverSide = loginModule.getServerSide();
136 Properties options = new Properties();
137 GerOptionType[] optionArray = loginModule.getOptionArray();
138 for (int j = 0; j < optionArray.length; j++) {
139 GerOptionType gerOptionType = optionArray[j];
140 String key = gerOptionType.getName();
141 String value = trim(gerOptionType.getStringValue());
142 options.setProperty(key, value);
143 }
144 loginModuleName = naming.createChildName(parentName, name, NameFactory.LOGIN_MODULE);
145 loginModuleReferencePatterns = new ReferencePatterns(loginModuleName);
146 GBeanData loginModuleGBeanData = new GBeanData(loginModuleName, LoginModuleGBean.GBEAN_INFO);
147 loginModuleGBeanData.setAttribute("loginDomainName", name);
148 loginModuleGBeanData.setAttribute("loginModuleClass", className);
149 loginModuleGBeanData.setAttribute("options", options);
150 loginModuleGBeanData.setAttribute("serverSide", Boolean.valueOf(serverSide));
151 loginModuleGBeanData.setAttribute("wrapPrincipals", Boolean.valueOf(wrapPrincipals));
152
153 context.addGBean(loginModuleGBeanData);
154 } else {
155 throw new DeploymentException("Unknown abstract login module type: " + abstractLoginModule.getClass());
156 }
157 AbstractName thisName;
158 thisName = naming.createChildName(parentName, name, "LoginModuleUse");
159 GBeanData loginModuleUseGBeanData = new GBeanData(thisName, JaasLoginModuleUse.GBEAN_INFO);
160 loginModuleUseGBeanData.setAttribute("controlFlag", controlFlag);
161 loginModuleUseGBeanData.setReferencePatterns("LoginModule", loginModuleReferencePatterns);
162 uses.add(loginModuleUseGBeanData);
163 }
164 for (int i = uses.size() - 1; i >= 0; i--) {
165 GBeanData data = (GBeanData) uses.get(i);
166 if (i > 0) {
167 ((GBeanData) uses.get(i - 1)).setReferencePattern("Next", data.getAbstractName());
168 }
169 context.addGBean(data);
170 }
171 }
172 catch (GBeanAlreadyExistsException e) {
173 throw new DeploymentException(e);
174 } finally {
175 xmlCursor.dispose();
176 }
177 return uses.size() == 0 ? null : new ReferencePatterns(((GBeanData) uses.get(0)).getAbstractName());
178 }
179
180 private String trim(String string) {
181 return string == null ? null : string.trim();
182 }
183
184 public static final GBeanInfo GBEAN_INFO;
185
186 private static final GReferenceInfo USE_REFERENCE_INFO;
187
188 static {
189 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(LoginConfigBuilder.class, "XmlReferenceBuilder");
190 infoBuilder.addAttribute("kernel", Kernel.class, false, false);
191 infoBuilder.setConstructor(new String[] {"kernel"});
192 infoBuilder.addInterface(XmlReferenceBuilder.class);
193 GBEAN_INFO = infoBuilder.getBeanInfo();
194
195 Set referenceInfos = JaasLoginModuleUse.GBEAN_INFO.getReferences();
196 GReferenceInfo found = null;
197 for (Iterator iterator = referenceInfos.iterator(); iterator.hasNext();) {
198 GReferenceInfo testReferenceInfo = (GReferenceInfo) iterator.next();
199 String testRefName = testReferenceInfo.getName();
200 if (testRefName.equals("LoginModule")) {
201 found = testReferenceInfo;
202 break;
203 }
204 }
205 if (found == null) {
206 throw new RuntimeException("Someone changed the gbeaninfo on JaasLoginModuleUse");
207 }
208 USE_REFERENCE_INFO = found;
209
210 }
211
212 public static GBeanInfo getGBeanInfo() {
213 return GBEAN_INFO;
214 }
215 }