View Javadoc

1   /**
2    * Copyright (C) 2005-2009 Alfresco Software Limited.
3    *
4    * This file is part of the Spring Surf Extension project.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.springframework.extensions.surf.support;
20  
21  import javax.servlet.http.HttpServletRequest;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.json.JSONArray;
26  import org.json.JSONObject;
27  import org.springframework.extensions.surf.FrameworkUtil;
28  import org.springframework.extensions.surf.RequestContext;
29  import org.springframework.extensions.surf.exception.UserFactoryException;
30  import org.springframework.extensions.surf.site.AlfrescoUser;
31  import org.springframework.extensions.surf.util.URLEncoder;
32  import org.springframework.extensions.webscripts.Status;
33  import org.springframework.extensions.webscripts.connector.AuthenticatingConnector;
34  import org.springframework.extensions.webscripts.connector.Connector;
35  import org.springframework.extensions.webscripts.connector.CredentialVault;
36  import org.springframework.extensions.webscripts.connector.Credentials;
37  import org.springframework.extensions.webscripts.connector.Response;
38  import org.springframework.extensions.webscripts.connector.User;
39  
40  /**
41   * This factory loads users from Alfresco, fetching their properties
42   * and so forth.  The data source is assumed to be a JSON provider.
43   * 
44   * By implementing this class, User derived objects are available to
45   * all downstream components and templates.  These components and
46   * templates can then consult the user profile as they execute.
47   * 
48   * The user is stored on the request context and can be fetched
49   * using context.getUser(). The user is also available in the root
50   * of the a script component context as 'user'. 
51   * 
52   * @author muzquiano
53   * @author kevinr
54   */
55  public class AlfrescoUserFactory extends AbstractUserFactory
56  {
57      private static final String JSON_RESPONSE_CODE_VALUE_OK = "OK";
58      private static final String JSON_RESPONSE_CODE = "code";
59  
60      private static Log logger = LogFactory.getLog(AlfrescoUserFactory.class);
61      
62      public static final String CM_AVATAR = "{http://www.alfresco.org/model/content/1.0}avatar";
63      public static final String CM_COMPANYEMAIL = "{http://www.alfresco.org/model/content/1.0}companyemail";
64      public static final String CM_COMPANYFAX = "{http://www.alfresco.org/model/content/1.0}companyfax";
65      public static final String CM_COMPANYTELEPHONE = "{http://www.alfresco.org/model/content/1.0}companytelephone";
66      public static final String CM_COMPANYPOSTCODE = "{http://www.alfresco.org/model/content/1.0}companypostcode";
67      public static final String CM_COMPANYADDRESS3 = "{http://www.alfresco.org/model/content/1.0}companyaddress3";
68      public static final String CM_COMPANYADDRESS2 = "{http://www.alfresco.org/model/content/1.0}companyaddress2";
69      public static final String CM_COMPANYADDRESS1 = "{http://www.alfresco.org/model/content/1.0}companyaddress1";
70      public static final String CM_INSTANTMSG = "{http://www.alfresco.org/model/content/1.0}instantmsg";
71      public static final String CM_SKYPE = "{http://www.alfresco.org/model/content/1.0}skype";
72      public static final String CM_MOBILE = "{http://www.alfresco.org/model/content/1.0}mobile";
73      public static final String CM_TELEPHONE = "{http://www.alfresco.org/model/content/1.0}telephone";
74      public static final String CM_PERSONDESCRIPTION = "{http://www.alfresco.org/model/content/1.0}persondescription";
75      public static final String CM_EMAIL = "{http://www.alfresco.org/model/content/1.0}email";
76      public static final String CM_LOCATION = "{http://www.alfresco.org/model/content/1.0}location";
77      public static final String CM_ORGANIZATION = "{http://www.alfresco.org/model/content/1.0}organization";
78      public static final String CM_JOBTITLE = "{http://www.alfresco.org/model/content/1.0}jobtitle";
79      public static final String CM_LASTNAME = "{http://www.alfresco.org/model/content/1.0}lastName";
80      public static final String CM_FIRSTNAME = "{http://www.alfresco.org/model/content/1.0}firstName";
81      public static final String CM_USERNAME = "{http://www.alfresco.org/model/content/1.0}userName";
82      private static final String ISADMIN = "isAdmin";
83      private static final String ISGUEST = "isGuest";
84      
85      public static final String ALFRESCO_ENDPOINT_ID = "alfresco";
86  
87  
88      /* (non-Javadoc)
89       * @see org.alfresco.web.site.UserFactory#authenticate(org.alfresco.web.site.RequestContext, javax.servlet.http.HttpServletRequest, java.lang.String, java.lang.String)
90       */
91      public boolean authenticate(HttpServletRequest request, String username, String password)
92      {
93          boolean authenticated = false;
94          try
95          {
96              // make sure our credentials are in the vault
97              CredentialVault vault = FrameworkUtil.getCredentialVault(request.getSession(), username);
98              Credentials credentials = vault.newCredentials(ALFRESCO_ENDPOINT_ID);
99              credentials.setProperty(Credentials.CREDENTIAL_USERNAME, username);
100             credentials.setProperty(Credentials.CREDENTIAL_PASSWORD, password);
101             
102             // build a connector whose connector session is bound to the current session
103             AuthenticatingConnector connector = (AuthenticatingConnector)
104                 FrameworkUtil.getConnector(request.getSession(), username, ALFRESCO_ENDPOINT_ID);
105             authenticated = connector.handshake();
106         }
107         catch (Throwable ex)
108         {
109             // many things might have happened
110             // an invalid ticket or perhaps a connectivity issue
111             // at any rate, we cannot authenticate
112             if (logger.isDebugEnabled())
113                 logger.debug("Exception in AlfrescoUserFactory.authenticate()", ex);
114         }
115         
116         return authenticated;
117     }
118 
119     /* (non-Javadoc)
120      * @see org.alfresco.web.site.UserFactory#loadUser(org.alfresco.web.site.RequestContext, java.lang.String)
121      */
122     public User loadUser(RequestContext context, String userId)
123         throws UserFactoryException
124     {
125         return loadUser(context, userId, null);
126     }
127     
128     /* (non-Javadoc)
129      * @see org.alfresco.web.site.UserFactory#loadUser(org.alfresco.web.site.RequestContext, java.lang.String, java.lang.String)
130      */
131     public User loadUser(RequestContext context, String userId, String endpointId)
132         throws UserFactoryException
133     {
134         if (endpointId == null)
135         {
136             endpointId = ALFRESCO_ENDPOINT_ID;
137         }
138         
139         AlfrescoUser user = null;
140         try
141         {
142             // ensure we bind the connector to the current user name - if this is the first load
143             // of a user we will use the userId as passed into the method 
144             String currentUserId = context.getUserId();
145             if (currentUserId == null)
146             {
147                 currentUserId = userId;
148             }
149             
150             // get a connector whose connector session is bound to the current session
151             Connector connector = FrameworkUtil.getConnector(
152                     context.getRequest().getSession(), currentUserId, endpointId);
153             
154             // build the REST URL to retrieve user details
155             String uri = "/webframework/content/metadata?user=" + URLEncoder.encode(userId);
156             
157             // invoke and check for OK response
158             Response response = connector.call(uri);
159             if (Status.STATUS_OK != response.getStatus().getCode())
160             {
161                 throw new UserFactoryException("Unable to create user - failed to retrieve user metadata: " + 
162                         response.getStatus().getMessage(), (Exception)response.getStatus().getException());
163             }
164             
165             // Load the user properties via the JSON parser
166             JSONObject json = new JSONObject(response.getResponse());
167             String code = json.getString(JSON_RESPONSE_CODE);
168             
169             if (JSON_RESPONSE_CODE_VALUE_OK.equals(code))
170             {
171                 JSONObject jsonData = json.getJSONObject("data");
172                 JSONObject properties = jsonData.getJSONObject("properties");
173                 
174                 // Construct the Alfresco User object based on the cm:person properties
175                 // ensure we have the correct username case
176                 user = constructUser(properties.getString(CM_USERNAME),
177                         properties.has(ISADMIN) && Boolean.parseBoolean(properties.getString(ISADMIN)),
178                     properties.has(ISGUEST) && Boolean.parseBoolean(properties.getString(ISGUEST)));
179                 user.setFirstName(properties.getString(CM_FIRSTNAME));
180                 user.setLastName(properties.getString(CM_LASTNAME));
181                 if (properties.has(CM_JOBTITLE))
182                 {
183                     user.setJobTitle(properties.getString(CM_JOBTITLE));
184                 }
185                 if (properties.has(CM_ORGANIZATION))
186                 {
187                     user.setOrganization(properties.getString(CM_ORGANIZATION));
188                 }
189                 if (properties.has(CM_LOCATION))
190                 {
191                     user.setLocation(properties.getString(CM_LOCATION));
192                 }
193                 if (properties.has(CM_EMAIL))
194                 {
195                     user.setEmail(properties.getString(CM_EMAIL));
196                 }
197                 if (properties.has(CM_PERSONDESCRIPTION))
198                 {
199                     user.setBiography(properties.getString(CM_PERSONDESCRIPTION));
200                 }
201                 if (properties.has(CM_TELEPHONE))
202                 {
203                     user.setTelephone(properties.getString(CM_TELEPHONE));
204                 }
205                 if (properties.has(CM_MOBILE))
206                 {
207                     user.setMobilePhone(properties.getString(CM_MOBILE));
208                 }
209                 if (properties.has(CM_SKYPE))
210                 {
211                     user.setSkype(properties.getString(CM_SKYPE));
212                 }
213                 if (properties.has(CM_INSTANTMSG))
214                 {
215                     user.setInstantMsg(properties.getString(CM_INSTANTMSG));
216                 }
217                 if (properties.has(CM_COMPANYADDRESS1))
218                 {
219                     user.setCompanyAddress1(properties.getString(CM_COMPANYADDRESS1));
220                 }
221                 if (properties.has(CM_COMPANYADDRESS2))
222                 {
223                     user.setCompanyAddress2(properties.getString(CM_COMPANYADDRESS2));
224                 }
225                 if (properties.has(CM_COMPANYADDRESS3))
226                 {
227                     user.setCompanyAddress3(properties.getString(CM_COMPANYADDRESS3));
228                 }
229                 if (properties.has(CM_COMPANYPOSTCODE))
230                 {
231                     user.setCompanyPostcode(properties.getString(CM_COMPANYPOSTCODE));
232                 }
233                 if (properties.has(CM_COMPANYTELEPHONE))
234                 {
235                     user.setCompanyTelephone(properties.getString(CM_COMPANYTELEPHONE));
236                 }
237                 if (properties.has(CM_COMPANYFAX))
238                 {
239                     user.setCompanyFax(properties.getString(CM_COMPANYFAX));
240                 }
241                 if (properties.has(CM_COMPANYEMAIL))
242                 {
243                     user.setCompanyEmail(properties.getString(CM_COMPANYEMAIL));
244                 }
245                 
246                 if (json.has("associations"))
247                 {
248                     JSONObject assocs = json.getJSONObject("associations");
249                     JSONArray array = assocs.getJSONArray(CM_AVATAR);
250                     if (array.length() != 0)
251                     {
252                         user.setAvatarRef(array.getString(0));
253                     }
254                 }
255             }
256             else
257             {
258                 String message = "none";
259                 if (json.has("message"))
260                 {
261                     message = json.getString("message");                    
262                 }
263                 
264                 throw new UserFactoryException("Code '" + code + "' received while loading user object.  Message: " + message);
265             }
266         }
267         catch (Exception ex)
268         {
269             // unable to read back the user json object
270             throw new UserFactoryException("Unable to retrieve user from repository", ex);
271         }
272 
273         return user;
274     }
275 
276     /**
277      * @param userId
278      * 
279      * @return the AlfrescoUser object
280      */
281     protected AlfrescoUser constructUser(String userId, boolean isAdmin, boolean isGuest)
282     {
283         return new AlfrescoUser(userId, isAdmin, isGuest);
284     }
285 }