Project

General

Profile

Download (12.6 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2012 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.api.application;
10

    
11
import java.util.Arrays;
12
import java.util.EnumSet;
13
import java.util.HashSet;
14
import java.util.List;
15
import java.util.Set;
16
import java.util.UUID;
17

    
18
import org.apache.log4j.Logger;
19
import org.springframework.beans.factory.annotation.Autowired;
20
import org.springframework.context.event.ContextRefreshedEvent;
21
import org.springframework.security.authentication.AuthenticationProvider;
22
import org.springframework.security.core.GrantedAuthority;
23
import org.springframework.transaction.PlatformTransactionManager;
24
import org.springframework.transaction.TransactionDefinition;
25
import org.springframework.transaction.TransactionStatus;
26
import org.springframework.transaction.support.DefaultTransactionDefinition;
27

    
28
import eu.etaxonomy.cdm.api.service.ICommonService;
29
import eu.etaxonomy.cdm.api.service.IGrantedAuthorityService;
30
import eu.etaxonomy.cdm.api.service.IGroupService;
31
import eu.etaxonomy.cdm.api.service.IUserService;
32
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
33
import eu.etaxonomy.cdm.common.monitor.NullProgressMonitor;
34
import eu.etaxonomy.cdm.config.Configuration;
35
import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
36
import eu.etaxonomy.cdm.model.common.Group;
37
import eu.etaxonomy.cdm.model.common.User;
38
import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
39
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
40
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
41
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionClass;
42
import eu.etaxonomy.cdm.persistence.hibernate.permission.Role;
43
import eu.etaxonomy.cdm.persistence.query.OrderHint;
44

    
45
/**
46
 * The <code>FirstDataInserter</code> is responsible for equipping a new and empty database with
47
 * the initial set of data need by the cdmlib. It operates not only on empty databases,
48
 * its methods are executed everytime the ApplicationContext has been started up, that is listens
49
 * for {@link ContextStartedEvent}s.
50
 * <p>
51
 * responsibilities:
52
 * <ul>
53
 * <li>User 'admin' and role 'ROLE_ADMIN'</li>
54
 * <li>cdm metadata</li>
55
 * <ul>
56
 * <p>
57
 * The <code>runAsAuthenticationProvider</code> must be set in a security application context, eg:
58
 * {@code
59
    <bean id="firstDataInserter" class="eu.etaxonomy.cdm.api.application.FirstDataInserter">
60
        <property name="runAsAuthenticationProvider" ref="runAsAuthenticationProvider"/>
61
    </bean>
62
    }
63
 *
64
 *
65
 *
66
 * @author a.kohlbecker
67
 * @date Oct 12, 2012
68
 *
69
 */
70
//@RunAs("ROLE_ADMIN") // seems to be broken in spring see: https://jira.springsource.org/browse/SEC-1671
71
public class FirstDataInserter extends AbstractDataInserter {
72

    
73
    /**
74
     *
75
     */
76
    private static final EnumSet<CRUD> CREATE_READ = EnumSet.of(CRUD.CREATE, CRUD.READ);
77
    private static final EnumSet<CRUD> UPDATE_DELETE = EnumSet.of(CRUD.UPDATE, CRUD.DELETE);
78
    private static final EnumSet<CRUD> CREATE_READ_UPDATE = EnumSet.of(CRUD.CREATE, CRUD.READ, CRUD.UPDATE);
79
    private static final EnumSet<CRUD> CREATE_READ_UPDATE_DELETE = EnumSet.of(CRUD.CREATE, CRUD.READ, CRUD.UPDATE, CRUD.DELETE);
80

    
81
    public static final Logger logger = Logger.getLogger(FirstDataInserter.class);
82

    
83
    public static final String[] EDITOR_GROUP_AUTHORITIES = new String[]{
84
            new CdmAuthority(CdmPermissionClass.REFERENCE, CREATE_READ).toString(),
85
            new CdmAuthority(CdmPermissionClass.TAXONNAME, CREATE_READ_UPDATE).toString(),
86
            new CdmAuthority(CdmPermissionClass.TEAMORPERSONBASE, CREATE_READ).toString(),
87
            new CdmAuthority(CdmPermissionClass.TAXONBASE, CREATE_READ_UPDATE_DELETE).toString(),
88
            new CdmAuthority(CdmPermissionClass.DESCRIPTIONBASE, CREATE_READ_UPDATE_DELETE).toString(),
89
            new CdmAuthority(CdmPermissionClass.DESCRIPTIONELEMENTBASE, CREATE_READ_UPDATE_DELETE).toString(),
90
            new CdmAuthority(CdmPermissionClass.SPECIMENOROBSERVATIONBASE, CREATE_READ_UPDATE_DELETE).toString(),
91
            new CdmAuthority(CdmPermissionClass.COLLECTION, CREATE_READ_UPDATE_DELETE).toString(),
92
    };
93

    
94
    /**
95
     * This group will in future replace the group Editor, see issue #7150
96
     */
97
    public static final String[] EDITOR_GROUP_EXTENDED_CREATE_GROUP_AUTHORITIES = new String[]{
98
            new CdmAuthority(CdmPermissionClass.REFERENCE, CREATE_READ).toString(),
99
            new CdmAuthority(CdmPermissionClass.TAXONNAME, CREATE_READ).toString(),
100
            new CdmAuthority(CdmPermissionClass.TEAMORPERSONBASE, CREATE_READ).toString(),
101
            new CdmAuthority(CdmPermissionClass.TAXONBASE, CREATE_READ).toString(),
102
            new CdmAuthority(CdmPermissionClass.DESCRIPTIONBASE, CREATE_READ).toString(),
103
            new CdmAuthority(CdmPermissionClass.DESCRIPTIONELEMENTBASE, CREATE_READ).toString(),
104
            new CdmAuthority(CdmPermissionClass.SPECIMENOROBSERVATIONBASE, CREATE_READ).toString(),
105
            new CdmAuthority(CdmPermissionClass.COLLECTION, CREATE_READ).toString(),
106
    };
107

    
108
    public static final String[] PROJECT_MANAGER_GROUP_AUTHORITIES = new String[]{
109
            new CdmAuthority(CdmPermissionClass.REFERENCE, UPDATE_DELETE).toString(),
110
            new CdmAuthority(CdmPermissionClass.TAXONNAME, EnumSet.of(CRUD.DELETE)).toString(),
111
            new CdmAuthority(CdmPermissionClass.TEAMORPERSONBASE, UPDATE_DELETE).toString(),
112
            Role.ROLE_PROJECT_MANAGER.toString(),
113
    };
114

    
115
    public static final String[] ADMIN_GROUP_AUTHORITIES = new String[]{
116
            Role.ROLE_ADMIN.toString()
117
    };
118

    
119
    @Autowired
120
    private ICommonService commonService;
121

    
122
    @Autowired
123
    private IUserService userService;
124

    
125
    @Autowired
126
    private IGroupService groupService;
127

    
128

    
129
    @Autowired
130
    private IGrantedAuthorityService grantedAuthorityService;
131

    
132
    // not to be autowired, since the FirstdataInserter must be usable without security
133
    private AuthenticationProvider runAsAuthenticationProvider = null;
134

    
135
    protected PlatformTransactionManager transactionManager;
136

    
137
    protected DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition();
138

    
139
    private IProgressMonitor progressMonitor = null;
140

    
141
    private boolean firstDataInserted = false;
142

    
143
    @Autowired
144
    public void setTransactionManager(PlatformTransactionManager transactionManager) {
145
        this.transactionManager = transactionManager;
146
    }
147

    
148
    public FirstDataInserter() {
149
        txDefinition.setName("FirstDataInserter.insertFirstData()");
150
        txDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
151
    }
152

    
153
    @Override
154
    public void onApplicationEvent(ContextRefreshedEvent event) {
155
        if(event.getApplicationContext() instanceof MonitoredGenericApplicationContext){
156
            progressMonitor = ((MonitoredGenericApplicationContext)event.getApplicationContext()).getCurrentMonitor();
157
            /* TODO set up work amount, currently the amount of work ticks is hard coded
158
             *      in {@link CdmApplicationControllersetNewDataSource}, but we need some means to register
159
             *      additional ticks.
160
             *      see http://dev.e-taxonomy.eu/trac/ticket/3140 (generic way to obtain work ticks of application startup for monitoring)
161
             *
162
             */
163
        } else {
164
            progressMonitor = new NullProgressMonitor();
165
        }
166

    
167
        insertFirstData();
168
    }
169

    
170

    
171
    private void insertFirstData() {
172

    
173
        // this ApplicationListener may be called multiple times in nested
174
        // application contexts like in web applications
175
        if(!firstDataInserted){
176

    
177
            runAsAuthentication(Role.ROLE_ADMIN);
178

    
179
            TransactionStatus txStatus = transactionManager.getTransaction(txDefinition);
180

    
181
            logger.info("inserting first data");
182
            checkAdminUser();
183
            checkDefaultGroups();
184
            checkMetadata();
185
            firstDataInserted = true;
186

    
187
            transactionManager.commit(txStatus);
188

    
189
            restoreAuthentication();
190

    
191
        } else {
192
            logger.debug("insertFirstData() already executed before, skipping this time");
193
        }
194
    }
195

    
196

    
197
    private void checkMetadata() {
198
        int metaDataCount = commonService.getCdmMetaData().size();
199
        if (metaDataCount == 0){
200
            progressMonitor.subTask("Creating Meta Data");
201
            createMetadata();
202
        }
203
    }
204

    
205
    private void checkAdminUser() {
206
        User admin = findFirstUser();
207

    
208
        if (admin == null){
209
            progressMonitor.subTask("Creating Admin User");
210
            admin = createAdminUser();
211
        } else {
212
            logger.info("Assuming first user '" + admin + "' is admin.");
213
        }
214

    
215
        checkAdminRole(admin);
216
        progressMonitor.worked(1);
217
    }
218

    
219
    private void checkDefaultGroups(){
220

    
221
        progressMonitor.subTask("Checking default groups");
222
        checkGroup(Group.GROUP_EDITOR_UUID, Group.GROUP_EDITOR_NAME, EDITOR_GROUP_AUTHORITIES);
223
        checkGroup(Group.GROUP_EDITOR_EXTENDED_CREATE_UUID, Group.GROUP_EDITOR_EXTENDED_CREATE_NAME, EDITOR_GROUP_EXTENDED_CREATE_GROUP_AUTHORITIES);
224
        checkGroup(Group.GROUP_PROJECT_MANAGER_UUID, Group.GROUP_PROJECT_MANAGER_NAME, PROJECT_MANAGER_GROUP_AUTHORITIES);
225
        checkGroup(Group.GROUP_ADMIN_UUID, Group.GROUP_ADMIN_NAME, ADMIN_GROUP_AUTHORITIES);
226
        progressMonitor.worked(1);
227
    }
228

    
229
    /**
230
     * @param newGroups
231
     * @param groupName
232
     * @param requiredAuthorities
233
     */
234
    private void checkGroup(UUID groupUuid, String groupName, String[] requiredAuthorities) {
235
        Group group = groupService.load(groupUuid);
236
        if(group == null){
237
            group = Group.NewInstance();
238
            group.setUuid(groupUuid);
239
            logger.info("New Group '" + groupName + "' created");
240
        }
241
        group.setName(groupName); // force default name
242

    
243
        Set<GrantedAuthority> grantedAuthorities = group.getGrantedAuthorities();
244

    
245
        for(String a : requiredAuthorities){
246
            boolean isMissing = true;
247
            for(GrantedAuthority ga : grantedAuthorities){
248
                if(a.equals(ga.getAuthority())){
249
                    isMissing = false;
250
                    break;
251
                }
252
            }
253
            if(isMissing){
254
                GrantedAuthorityImpl newGa = grantedAuthorityService.findAuthorityString(a);
255

    
256
                if (newGa == null){
257
                    newGa = GrantedAuthorityImpl.NewInstance(a);
258
                }
259

    
260
                group.addGrantedAuthority(newGa);
261
                logger.info("New GrantedAuthority '" + a + "' added  to '" + groupName + "'");
262
            }
263
        }
264

    
265
        groupService.merge(group, true);
266
        logger.info("Check of group  '" + groupName + "' done");
267
    }
268

    
269
    /**
270
     * @return
271
     */
272
    private User findFirstUser() {
273
        User firstUser = null;
274
        List<User> users = userService.list(null, 1, null, Arrays.asList(new OrderHint[]{new OrderHint("id", OrderHint.SortOrder.ASCENDING)}), null);
275
        if(users.size() > 0){
276
            firstUser = users.get(0);
277
        }
278
        return firstUser;
279
    }
280

    
281
    private User createAdminUser(){
282

    
283
        User admin = User.NewInstance(Configuration.adminLogin, Configuration.adminPassword);
284
        userService.save(admin);
285
        logger.info("user '" + Configuration.adminLogin + "' created.");
286
        return admin;
287
    }
288

    
289
    private void checkAdminRole(User admin) {
290
        Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
291

    
292

    
293
        authorities = (Set<GrantedAuthority>) admin.getAuthorities();
294

    
295
        boolean hasRoleAdmin = false;
296
        for(GrantedAuthority grau : authorities){
297
            if(grau.getAuthority().contentEquals(Role.ROLE_ADMIN.getAuthority())){
298
                hasRoleAdmin = true;
299
                break;
300
            }
301
        }
302

    
303
        if(!hasRoleAdmin){
304
            authorities.add(getRoleAdmin());
305
            admin.setGrantedAuthorities(authorities);
306
            progressMonitor.subTask("Creating Admins Role");
307
            userService.saveOrUpdate(admin);
308
            logger.info("Role " + Role.ROLE_ADMIN.getAuthority() + " for user '" + Configuration.adminLogin + "' created and added");
309
        }
310
    }
311

    
312
    /**
313
     * @return
314
     */
315
    private GrantedAuthorityImpl getRoleAdmin() {
316
        GrantedAuthorityImpl role_admin = grantedAuthorityService.find(Role.ROLE_ADMIN.getUuid());
317
        if(role_admin == null){
318
            role_admin = Role.ROLE_ADMIN.asNewGrantedAuthority();
319
        }
320
        return role_admin;
321
    }
322

    
323
    private void createMetadata(){
324
        List<CdmMetaData> metaData = CdmMetaData.defaultMetaData();
325
        commonService.saveAllMetaData(metaData);
326
        logger.info("Metadata created.");
327
    }
328

    
329
}
(5-5/9)