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 }