Project

General

Profile

Download (10.3 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.HashSet;
13
import java.util.List;
14
import java.util.Set;
15
import java.util.UUID;
16

    
17
import org.apache.log4j.Logger;
18
import org.springframework.beans.factory.annotation.Autowired;
19
import org.springframework.context.event.ContextRefreshedEvent;
20
import org.springframework.context.event.ContextStartedEvent;
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.Role;
40
import eu.etaxonomy.cdm.persistence.query.OrderHint;
41

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

    
70
    public static final Logger logger = Logger.getLogger(FirstDataInserter.class);
71

    
72
    public static final String[] EDITOR_GROUP_AUTHORITIES = new String[]{
73
            "REFERENCE.[CREATE,READ]",
74
            "TAXONNAME.[CREATE,READ,UPDATE]",
75
            "TEAMORPERSONBASE.[CREATE,READ]",
76
            "TAXONBASE.[CREATE,UPDATE,DELETE,READ]",
77
            "DESCRIPTIONBASE.[CREATE,UPDATE,DELETE,READ]",
78
            "DESCRIPTIONELEMENTBASE.[CREATE,UPDATE,DELETE,READ]",
79
    };
80

    
81
    public static final String[] PROJECT_MANAGER_GROUP_AUTHORITIES = new String[]{
82
            "REFERENCE.[UPDATE,DELETE]",
83
            "TAXONNAME.[DELETE]",
84
            "TEAMORPERSONBASE.[UPDATE,DELETE]",
85
            Role.ROLE_PROJECT_MANAGER.toString(),
86
    };
87

    
88
    public static final String[] ADMIN_GROUP_AUTHORITIES = new String[]{
89
            Role.ROLE_ADMIN.toString()
90
    };
91

    
92
    @Autowired
93
    private ICommonService commonService;
94

    
95
    @Autowired
96
    private IUserService userService;
97

    
98
    @Autowired
99
    private IGroupService groupService;
100

    
101

    
102
    @Autowired
103
    private IGrantedAuthorityService grantedAuthorityService;
104

    
105
    // not to be autowired, since the FirstdataInserter must be usable without security
106
    private AuthenticationProvider runAsAuthenticationProvider = null;
107

    
108
    protected PlatformTransactionManager transactionManager;
109

    
110
    protected DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition();
111

    
112
    private IProgressMonitor progressMonitor = null;
113

    
114
    private boolean firstDataInserted = false;
115

    
116
    @Autowired
117
    public void setTransactionManager(PlatformTransactionManager transactionManager) {
118
        this.transactionManager = transactionManager;
119
    }
120

    
121
    public FirstDataInserter() {
122
        txDefinition.setName("FirstDataInserter.insertFirstData()");
123
        txDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
124
    }
125

    
126
    @Override
127
    public void onApplicationEvent(ContextRefreshedEvent event) {
128
        if(event.getApplicationContext() instanceof MonitoredGenericApplicationContext){
129
            progressMonitor = ((MonitoredGenericApplicationContext)event.getApplicationContext()).getCurrentMonitor();
130
            /* TODO set up work amount, currently the amount of work ticks is hard coded
131
             *      in {@link CdmApplicationControllersetNewDataSource}, but we need some means to register
132
             *      additional ticks.
133
             *      see http://dev.e-taxonomy.eu/trac/ticket/3140 (generic way to obtain work ticks of application startup for monitoring)
134
             *
135
             */
136
        } else {
137
            progressMonitor = new NullProgressMonitor();
138
        }
139

    
140
        insertFirstData();
141
    }
142

    
143

    
144
    private void insertFirstData() {
145

    
146
        // this ApplicationListener may be called multiple times in nested
147
        // application contexts like in web applications
148
        if(!firstDataInserted){
149

    
150
            runAsAuthentication(Role.ROLE_ADMIN);
151

    
152
            TransactionStatus txStatus = transactionManager.getTransaction(txDefinition);
153

    
154
            logger.info("inserting first data");
155
            checkAdminUser();
156
            checkDefaultGroups();
157
            checkMetadata();
158
            firstDataInserted = true;
159

    
160
            transactionManager.commit(txStatus);
161

    
162
            restoreAuthentication();
163

    
164
        } else {
165
            logger.debug("insertFirstData() already executed before, skipping this time");
166
        }
167
    }
168

    
169

    
170
    private void checkMetadata() {
171
        int metaDataCount = commonService.getCdmMetaData().size();
172
        if (metaDataCount == 0){
173
            progressMonitor.subTask("Creating Meta Data");
174
            createMetadata();
175
        }
176
    }
177

    
178
    private void checkAdminUser() {
179
        User admin = findFirstUser();
180

    
181
        if (admin == null){
182
            progressMonitor.subTask("Creating Admin User");
183
            admin = createAdminUser();
184
        } else {
185
            logger.info("Assuming first user '" + admin + "' is admin.");
186
        }
187

    
188
        checkAdminRole(admin);
189
        progressMonitor.worked(1);
190
    }
191

    
192
    private void checkDefaultGroups(){
193

    
194
        progressMonitor.subTask("Checking default groups");
195
        checkGroup(Group.GROUP_EDITOR_UUID, "Editor", EDITOR_GROUP_AUTHORITIES);
196
        checkGroup(Group.GROUP_PROJECT_MANAGER_UUID, "ProjectManager", PROJECT_MANAGER_GROUP_AUTHORITIES);
197
        checkGroup(Group.GROUP_ADMIN_UUID, "Admin", ADMIN_GROUP_AUTHORITIES);
198
        progressMonitor.worked(1);
199
    }
200

    
201
    /**
202
     * @param newGroups
203
     * @param groupName
204
     * @param requiredAuthorities
205
     */
206
    private void checkGroup(UUID groupUuid, String groupName, String[] requiredAuthorities) {
207
        Group group = groupService.load(groupUuid);
208
        if(group == null){
209
            group = Group.NewInstance();
210
            group.setUuid(groupUuid);
211
            logger.info("New Group '" + groupName + "' created");
212
        }
213
        group.setName(groupName); // force name
214

    
215
        Set<GrantedAuthority> grantedAuthorities = group.getGrantedAuthorities();
216

    
217
        for(String a : requiredAuthorities){
218
            boolean isMissing = true;
219
            for(GrantedAuthority ga : grantedAuthorities){
220
                if(a.equals(ga.getAuthority())){
221
                    isMissing = false;
222
                    break;
223
                }
224
            }
225
            if(isMissing){
226
                GrantedAuthorityImpl newGa = grantedAuthorityService.findAuthorityString(a);
227

    
228
                if (newGa == null){
229
                    newGa = GrantedAuthorityImpl.NewInstance(a);
230
                }
231

    
232
                group.addGrantedAuthority(newGa);
233
                logger.info("New GrantedAuthority '" + a + "' added  to '" + groupName + "'");
234
            }
235
        }
236

    
237
        groupService.merge(group, true);
238
        logger.info("Check of group  '" + groupName + "' done");
239
    }
240

    
241
    /**
242
     * @return
243
     */
244
    private User findFirstUser() {
245
        User firstUser = null;
246
        List<User> users = userService.list(null, 1, null, Arrays.asList(new OrderHint[]{new OrderHint("id", OrderHint.SortOrder.ASCENDING)}), null);
247
        if(users.size() > 0){
248
            firstUser = users.get(0);
249
        }
250
        return firstUser;
251
    }
252

    
253
    private User createAdminUser(){
254

    
255
        User admin = User.NewInstance(Configuration.adminLogin, Configuration.adminPassword);
256
        userService.save(admin);
257
        logger.info("user '" + Configuration.adminLogin + "' created.");
258
        return admin;
259
    }
260

    
261
    private void checkAdminRole(User admin) {
262
        Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
263

    
264

    
265
        authorities = (Set<GrantedAuthority>) admin.getAuthorities();
266

    
267
        boolean hasRoleAdmin = false;
268
        for(GrantedAuthority grau : authorities){
269
            if(grau.getAuthority().contentEquals(Role.ROLE_ADMIN.getAuthority())){
270
                hasRoleAdmin = true;
271
                break;
272
            }
273
        }
274

    
275
        if(!hasRoleAdmin){
276
            authorities.add(getRoleAdmin());
277
            admin.setGrantedAuthorities(authorities);
278
            progressMonitor.subTask("Creating Admins Role");
279
            userService.saveOrUpdate(admin);
280
            logger.info("Role " + Role.ROLE_ADMIN.getAuthority() + " for user '" + Configuration.adminLogin + "' created and added");
281
        }
282
    }
283

    
284
    /**
285
     * @return
286
     */
287
    private GrantedAuthorityImpl getRoleAdmin() {
288
        GrantedAuthorityImpl role_admin = grantedAuthorityService.find(Role.ROLE_ADMIN.getUuid());
289
        if(role_admin == null){
290
            role_admin = Role.ROLE_ADMIN.asNewGrantedAuthority();
291
        }
292
        return role_admin;
293
    }
294

    
295
    private void createMetadata(){
296
        List<CdmMetaData> metaData = CdmMetaData.defaultMetaData();
297
        commonService.saveAllMetaData(metaData);
298
        logger.info("Metadata created.");
299
    }
300

    
301
}
(5-5/9)