4e5b1da7b6a2a1540c3fb9c11bab938993f0dd09
[photos] / src / main / java / org / wamblee / photos / model / plumbing / Producer.java
1 /*
2  * Copyright 2005-2013 the original author or authors.
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.wamblee.photos.model.plumbing;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.security.Principal;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.logging.Logger;
24
25 import javax.enterprise.context.ApplicationScoped;
26 import javax.enterprise.context.SessionScoped;
27 import javax.enterprise.inject.Produces;
28 import javax.inject.Inject;
29 import javax.persistence.EntityManager;
30 import javax.persistence.PersistenceContext;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpSession;
33
34 import org.wamblee.cache.Cache;
35 import org.wamblee.cache.EhCache;
36 import org.wamblee.io.ClassPathResource;
37 import org.wamblee.io.InputResource;
38 import org.wamblee.photos.concurrent.ConcurrentAlbum;
39 import org.wamblee.photos.model.Album;
40 import org.wamblee.photos.model.PhotoEntry;
41 import org.wamblee.photos.model.authorization.AuthorizedAlbum;
42 import org.wamblee.photos.model.filesystem.FileSystemAlbum;
43 import org.wamblee.photos.security.PageAuthorizationRule;
44 import org.wamblee.photos.security.PhotoAuthorizationRule;
45 import org.wamblee.photos.wicket.HomePage;
46 import org.wamblee.security.authentication.GroupSet;
47 import org.wamblee.security.authentication.Md5HexMessageDigester;
48 import org.wamblee.security.authentication.MessageDigester;
49 import org.wamblee.security.authentication.NameValidator;
50 import org.wamblee.security.authentication.RegexpNameValidator;
51 import org.wamblee.security.authentication.User;
52 import org.wamblee.security.authentication.UserAccessor;
53 import org.wamblee.security.authentication.UserAdminInitializer;
54 import org.wamblee.security.authentication.UserAdministration;
55 import org.wamblee.security.authentication.UserAdministrationImpl;
56 import org.wamblee.security.authentication.UserSet;
57 import org.wamblee.security.authentication.jpa.JpaGroupSet;
58 import org.wamblee.security.authentication.jpa.JpaUserSet;
59 import org.wamblee.security.authorization.AbstractAuthorizationRule;
60 import org.wamblee.security.authorization.AllOperation;
61 import org.wamblee.security.authorization.AnyUserCondition;
62 import org.wamblee.security.authorization.AuthorizationInitializer;
63 import org.wamblee.security.authorization.AuthorizationResult;
64 import org.wamblee.security.authorization.AuthorizationService;
65 import org.wamblee.security.authorization.CreateOperation;
66 import org.wamblee.security.authorization.DefaultOperationRegistry;
67 import org.wamblee.security.authorization.DeleteOperation;
68 import org.wamblee.security.authorization.GroupUserCondition;
69 import org.wamblee.security.authorization.Operation;
70 import org.wamblee.security.authorization.OperationRegistry;
71 import org.wamblee.security.authorization.ReadOperation;
72 import org.wamblee.security.authorization.WriteOperation;
73 import org.wamblee.security.authorization.jpa.JpaAuthorizationService;
74
75 /**
76  * @author Erik Brakkee
77  * 
78  */
79 public class Producer {
80
81     private static final Logger LOGGER = Logger.getLogger(Producer.class
82         .getName());
83
84     private static final String APP_CONFIG_RESOURCE = "META-INF/org.wamblee.photos.properties";
85
86     @Inject
87     private HttpServletRequest request;
88
89     @Inject
90     private HttpSession session;
91
92     @PersistenceContext
93     private EntityManager entityManager;
94
95     // Created by this producer.
96
97     @Inject
98     private UserAdministration userAdmin;
99
100     @Inject
101     private AuthorizationService authorizationService;
102
103     @Inject
104     @AllPhotos
105     private Album allPhotos;
106
107     private Configuration getCOnfiguration() {
108         LOGGER.info("Initializing configuration");
109         Configuration config;
110         try {
111             config = new Configuration(new ClassPathResource(
112                 APP_CONFIG_RESOURCE).getInputStream());
113         } catch (IOException e) {
114             throw new RuntimeException(
115                 "Could not read application configuration property classpath resource " +
116                     APP_CONFIG_RESOURCE, e);
117         }
118         return config;
119     }
120
121     @Produces
122     @ApplicationScoped
123     public UserAdministration getUserAdmin() {
124         LOGGER.info("Initializing user administration");
125         try {
126             NameValidator passwordvalidator = new RegexpNameValidator(".{5,}",
127                 "INVALID_PASSWORD", "Password must have at least 5 characters");
128             InputResource cacheConfig = new ClassPathResource(
129                 "META-INF/ehcache.xml");
130             Cache<String, User> userCache = new EhCache(cacheConfig, "users");
131             MessageDigester passwordEncoder = new Md5HexMessageDigester();
132             UserSet userset = new JpaUserSet(userCache, passwordvalidator,
133                 passwordEncoder, entityManager);
134             GroupSet groupset = new JpaGroupSet(entityManager);
135             NameValidator uservalidator = new RegexpNameValidator(
136                 "[a-zA-Z]+[a-zA-Z0-9]*", "INVALID_USERNAME",
137                 "User name must consist of alphanumeric characters only");
138             NameValidator groupvalidator = new RegexpNameValidator(
139                 "[a-zA-Z]+[a-zA-Z0-9]*", "INVALID_GROUPNAME",
140                 "Group name must consist of alphanumeric characters only");
141
142             UserAdministration admin = new UserAdministrationImpl(userset,
143                 groupset, uservalidator, groupvalidator);
144             UserAdminInitializer initializer = new UserAdminInitializer(admin,
145                 new String[] { "erik", "admin" }, new String[] { "users",
146                     "administrators" }, new String[] { "abc123", "abc123" });
147             return admin;
148         } catch (IOException e) {
149             throw new RuntimeException(
150                 "Could not initialize user administration", e);
151         }
152     }
153
154     @Produces
155     @ApplicationScoped
156     public AuthorizationService getAuthorizationService() {
157         OperationRegistry registry = new DefaultOperationRegistry(
158             new Operation[] { new AllOperation(), new CreateOperation(),
159                 new DeleteOperation(), new ReadOperation(),
160                 new WriteOperation() });
161         UserAccessor userAccessor = new UserAccessor() {
162
163             @Override
164             public String getCurrentUser() {
165                 Principal principal = request.getUserPrincipal();
166                 if (principal == null) {
167                     return null;
168                 }
169                 return principal.getName();
170             }
171         };
172         AuthorizationService service = new JpaAuthorizationService("DEFAULT",
173             entityManager, userAccessor, userAdmin, 10000);
174
175         AnyUserCondition anyUserCondition = new AnyUserCondition();
176         GroupUserCondition adminUserCondition = new GroupUserCondition(
177             "administrators");
178
179         PhotoAuthorizationRule photoEntryRule = new PhotoAuthorizationRule();
180
181         // Pages that allow access by any authenticated user
182         PageAuthorizationRule anyUserPageRule = new PageAuthorizationRule(
183             AuthorizationResult.GRANTED, anyUserCondition, HomePage.class);
184
185         PageAuthorizationRule adminPageRule = new PageAuthorizationRule(
186             AuthorizationResult.GRANTED, adminUserCondition);
187
188         AuthorizationInitializer initializer = new AuthorizationInitializer(
189             service, new AbstractAuthorizationRule[] { photoEntryRule,
190                 anyUserPageRule, adminPageRule });
191
192         return service;
193     }
194
195     @Produces
196     @ApplicationScoped
197     @AllPhotos
198     public Album getAllPhotos() {
199         LOGGER.info("Initializing photo album");
200
201         try {
202             File dir = new File(getCOnfiguration().getPath());
203             InputResource cacheConfig = new ClassPathResource(
204                 "META-INF/ehcache.xml");
205             Cache<String, ArrayList<PhotoEntry>> photoCache = new EhCache<String, ArrayList<PhotoEntry>>(
206                 cacheConfig, "photos");
207             Album fileSystemAlbum = new FileSystemAlbum(dir, "/", photoCache);
208             Album concurrentAlbum = new ConcurrentAlbum(fileSystemAlbum);
209
210             return concurrentAlbum;
211         } catch (IOException e) {
212             throw new RuntimeException("Could not initialize photo album", e);
213         }
214     }
215
216     @Produces
217     @SessionScoped
218     @AuthorizedPhotos
219     public Album getAuthorizedAlbum() {
220         LOGGER.info("Initializing authorized photos for current session");
221         try {
222             InputResource cacheConfig = new ClassPathResource(
223                 "META-INF/ehcache.xml");
224             Cache<String, User> userCache = new EhCache(cacheConfig, "users");
225             Cache authorizedPhotoCache = new EhCache(cacheConfig, "photos");
226
227             AuthorizedAlbum album = new AuthorizedAlbum(allPhotos,
228                 authorizationService, authorizedPhotoCache, session.getId());
229             return album;
230         } catch (IOException e) {
231             throw new RuntimeException("Problem initializing authorized album",
232                 e);
233         }
234     }
235
236     @Produces
237     @SessionScoped
238     public User getUser() {
239         LOGGER.info("Initializing user object for current session");
240
241         Principal userPrincipal = request.getUserPrincipal();
242         if (userPrincipal == null) {
243             // CDI: cannot return null from this method.
244             throw new RuntimeException("No authenticated user");
245         }
246         String username = userPrincipal.getName();
247         List<User> users = entityManager
248             .createNamedQuery(User.QUERY_FIND_BY_NAME)
249             .setParameter(User.NAME_PARAM, username).getResultList();
250         if (users.size() > 1) {
251             throw new RuntimeException("More than one user found for '" +
252                 username + "'");
253         }
254         if (users.isEmpty()) {
255             throw new RuntimeException("No authenticated user");
256         }
257         return users.get(0);
258     }
259
260 }