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