View Javadoc
1   /*
2    * Copyright 2001-2009 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.juddi.v3.auth;
17  
18  import java.util.HashMap;
19  import java.util.Hashtable;
20  import java.util.Map;
21  
22  import javax.naming.Context;
23  import javax.naming.NamingException;
24  import javax.naming.ldap.InitialLdapContext;
25  import javax.naming.ldap.LdapContext;
26  import javax.persistence.EntityManager;
27  import javax.persistence.EntityTransaction;
28  import javax.xml.ws.WebServiceContext;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  
33  import org.apache.juddi.config.AppConfig;
34  import org.apache.juddi.config.PersistenceManager;
35  import org.apache.juddi.config.Property;
36  import org.apache.juddi.model.Publisher;
37  import org.apache.juddi.model.UddiEntityPublisher;
38  import org.apache.juddi.v3.error.AuthenticationException;
39  import org.apache.juddi.v3.error.ErrorMessage;
40  import org.apache.juddi.v3.error.FatalErrorException;
41  import org.apache.juddi.v3.error.UnknownUserException;
42  
43  import org.apache.commons.configuration.ConfigurationException;
44  
45  /**
46   * This is an expanded implementation of jUDDI's Authenticator interface, that uses the
47   * LDAP with string formatting to enable users to sign in as a common name instead of the full
48   * distinguished name.
49   * 
50   * Usage:
51   * 
52   * To use this class you must add the following properties to the
53   * juddiv3.xml file:
54   * 
55   * # The LDAP Authenticator
56   * juddi/auth/class=org.apache.juddi.v3.auth.LdapSimpleAuthenticator
57   * 
58   * # LDAP authentication URL
59   * juddi/auth/url=ldap://localhost:389
60   *
61   * juddi/auth/ldapexp=CN=%s, OU=Users,DC=Domain, etc
62   * 
63   * This authenticator assumes that the publisher username can be reformatted to a LDAP 
64   * common name. This is common for Microsoft based LDAPs. The configuration item juddi.authenticator.ldapexp
65   * should contain exactly one instance of "%s", which is replaced by the requestor's username
66   *
67   *
68   * @author <a href="mailto:alexoree@apache.org">Alex O'Ree</a>
69   */
70  public class LdapExpandedAuthenticator implements Authenticator {
71      private Log logger = LogFactory.getLog(this.getClass());
72  
73      private LdapContext ctx = null;
74      //this needs to be a Hashtable, HashMap won't work here
75      private Hashtable<String, String> env = null;
76      private String url = null;
77      
78      private static final String DEFAULT_URL = "ldap://localhost:389";
79      
80      public LdapExpandedAuthenticator() throws NamingException, ConfigurationException {
81      	String authURL = null;
82      	try {
83      		authURL = AppConfig.getConfiguration().getString(Property.JUDDI_AUTHENTICATOR_URL, DEFAULT_URL);
84      	} catch (ConfigurationException ce) {
85      		logger.error("Configuration exception occurred retrieving: " + Property.JUDDI_AUTHENTICATOR_URL);
86      		throw new NamingException(Property.JUDDI_AUTHENTICATOR_URL + " missing from config or config is not available.");
87      	}
88      	init(authURL);
89      }
90      
91      public LdapExpandedAuthenticator(String url) throws NamingException, ConfigurationException {
92      	init(url);
93      }
94  
95      public void init(String url) throws NamingException, ConfigurationException {
96          env = new Hashtable<String, String>();
97          env.put(Context.INITIAL_CONTEXT_FACTORY, AppConfig.getConfiguration().getString(Property.JUDDI_AUTHENTICATOR_INITIAL_CONTEXT, "com.sun.jndi.ldap.LdapCtxFactory"));
98          env.put(Context.SECURITY_AUTHENTICATION, AppConfig.getConfiguration().getString(Property.JUDDI_AUTHENTICATOR_STYLE, "simple"));
99          env.put(Context.PROVIDER_URL, url); // organization ldap url, example ldap://localhost:389
100 
101         this.url = url;
102         
103         try {
104             ctx = new InitialLdapContext(env, null);
105         } catch (NamingException e) {
106             logger.error("Naming exception " + e);
107             throw e;
108         }
109     }
110     
111     public String authenticate(String authorizedName, String cred)
112             throws AuthenticationException, FatalErrorException {
113         if (authorizedName == null || "".equals(authorizedName)) {
114             throw new UnknownUserException(new ErrorMessage("errors.auth.NoPublisher", authorizedName));
115         }
116 
117         boolean isLdapUser = false;
118         
119         int MaxBindingsPerService = -1;
120         int MaxServicesPerBusiness = -1;
121         int MaxTmodels = -1;
122         int MaxBusinesses = -1;
123         try {
124                 MaxBindingsPerService = AppConfig.getConfiguration().getInt(Property.JUDDI_MAX_BINDINGS_PER_SERVICE, -1);
125                 MaxServicesPerBusiness = AppConfig.getConfiguration().getInt(Property.JUDDI_MAX_SERVICES_PER_BUSINESS, -1);
126                 MaxTmodels = AppConfig.getConfiguration().getInt(Property.JUDDI_MAX_TMODELS_PER_PUBLISHER, -1);
127                 MaxBusinesses = AppConfig.getConfiguration().getInt(Property.JUDDI_MAX_BUSINESSES_PER_PUBLISHER, -1);
128         } catch (Exception ex) {
129                 MaxBindingsPerService = -1;
130                 MaxServicesPerBusiness = -1;
131                 MaxTmodels = -1;
132                 MaxBusinesses = -1;
133                 logger.error("config exception! " + authorizedName, ex);
134         }
135 
136         try {
137             env = new Hashtable<String, String>();
138             env.put(Context.INITIAL_CONTEXT_FACTORY, AppConfig.getConfiguration().getString(Property.JUDDI_AUTHENTICATOR_INITIAL_CONTEXT, "com.sun.jndi.ldap.LdapCtxFactory"));
139             env.put(Context.SECURITY_AUTHENTICATION, AppConfig.getConfiguration().getString(Property.JUDDI_AUTHENTICATOR_STYLE, "simple"));
140             
141             env.put(Context.PROVIDER_URL, url); // organization ldap url, example ldap://localhost:389
142             String format = String.format(AppConfig.getConfiguration().getString(Property.JUDDI_AUTHENTICATOR_LDAP_EXPANDED_STR), authorizedName);
143             
144             env.put(Context.SECURITY_PRINCIPAL, format);
145             env.put(Context.SECURITY_CREDENTIALS, cred);
146             ctx = new InitialLdapContext(env, null);
147             isLdapUser = true;
148             logger.info(authorizedName + " is authenticated");
149            
150         } catch (ConfigurationException e) {
151             logger.error(authorizedName + " is not authenticated", e);
152             throw new UnknownUserException(new ErrorMessage("errors.auth.NoPublisher", authorizedName));
153         }
154         catch (NamingException e) {
155             logger.error(authorizedName + " is not authenticated");
156             throw new UnknownUserException(new ErrorMessage("errors.auth.NoPublisher", authorizedName));
157         }finally {
158             try {
159                 ctx.close();
160             } catch (NamingException e) {
161                 logger.error("Context close failure " + e);
162             }
163         }
164 
165         if (isLdapUser) {
166             EntityManager em = PersistenceManager.getEntityManager();
167             EntityTransaction tx = em.getTransaction();
168             try {
169                 tx.begin();
170                 Publisher publisher = em.find(Publisher.class, authorizedName);
171                 if (publisher == null) {
172                     logger.warn("Publisher was not found in the database, adding the publisher in on the fly.");
173                     publisher = new Publisher();
174                     publisher.setAuthorizedName(authorizedName);
175                     publisher.setIsAdmin("false");
176                     publisher.setIsEnabled("true");
177                     publisher.setMaxBindingsPerService(MaxBindingsPerService);
178                     publisher.setMaxBusinesses(MaxBusinesses);
179                     publisher.setMaxServicesPerBusiness(MaxServicesPerBusiness);
180                     publisher.setMaxTmodels(MaxTmodels);
181                     publisher.setPublisherName("Unknown");
182                     em.persist(publisher);
183                     tx.commit();
184                 }
185             } finally {
186                 if (tx.isActive()) {
187                     tx.rollback();
188                 }
189                 em.close();
190             }
191         } else {
192             throw new UnknownUserException(new ErrorMessage("errors.auth.NoPublisher", authorizedName));
193         }
194         return authorizedName;
195     }
196 
197     public UddiEntityPublisher identify(String authInfo, String authorizedName, WebServiceContext ctx) throws AuthenticationException, FatalErrorException {
198         EntityManager em = PersistenceManager.getEntityManager();
199         EntityTransaction tx = em.getTransaction();
200         try {
201             tx.begin();
202             Publisher publisher = em.find(Publisher.class, authorizedName);
203             if (publisher == null)
204                 throw new UnknownUserException(new ErrorMessage("errors.auth.NoPublisher", authorizedName));
205             return publisher;
206         } finally {
207             if (tx.isActive()) {
208                 tx.rollback();
209             }
210             em.close();
211         }
212     }
213 }