Project

General

Profile

Download (11.3 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 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

    
10
package eu.etaxonomy.cdm.model.permission;
11

    
12
import java.util.Collection;
13
import java.util.HashSet;
14
import java.util.Set;
15

    
16
import javax.persistence.Column;
17
import javax.persistence.Entity;
18
import javax.persistence.FetchType;
19
import javax.persistence.ManyToMany;
20
import javax.persistence.OneToOne;
21
import javax.persistence.Table;
22
import javax.persistence.Transient;
23
import javax.validation.constraints.NotNull;
24
import javax.validation.constraints.Pattern;
25
import javax.xml.bind.annotation.XmlAccessType;
26
import javax.xml.bind.annotation.XmlAccessorType;
27
import javax.xml.bind.annotation.XmlElement;
28
import javax.xml.bind.annotation.XmlElementWrapper;
29
import javax.xml.bind.annotation.XmlIDREF;
30
import javax.xml.bind.annotation.XmlRootElement;
31
import javax.xml.bind.annotation.XmlSchemaType;
32
import javax.xml.bind.annotation.XmlTransient;
33
import javax.xml.bind.annotation.XmlType;
34

    
35
import org.apache.commons.lang3.StringUtils;
36
import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;
37
import org.hibernate.annotations.Cascade;
38
import org.hibernate.annotations.CascadeType;
39
import org.hibernate.envers.Audited;
40
import org.hibernate.envers.NotAudited;
41
import org.hibernate.search.annotations.Analyze;
42
import org.hibernate.search.annotations.Field;
43
import org.hibernate.search.annotations.IndexedEmbedded;
44
import org.springframework.security.core.Authentication;
45
import org.springframework.security.core.GrantedAuthority;
46
import org.springframework.security.core.context.SecurityContextHolder;
47
import org.springframework.security.core.userdetails.UserDetails;
48

    
49
import eu.etaxonomy.cdm.model.agent.Person;
50
import eu.etaxonomy.cdm.model.common.CdmBase;
51
import eu.etaxonomy.cdm.validation.Level2;
52
import eu.etaxonomy.cdm.validation.annotation.ValidPassword;
53

    
54
@XmlAccessorType(XmlAccessType.FIELD)
55
@XmlType(name = "User", propOrder = {
56
    "username",
57
    "password",
58
    "salt",
59
    "emailAddress",
60
    "grantedAuthorities",
61
    "authorities",
62
    "groups",
63
    "enabled",
64
    "accountNonExpired",
65
    "credentialsNonExpired",
66
    "accountNonLocked",
67
    "person"
68
})
69
@XmlRootElement(name = "User")
70
@Entity
71
//@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
72
//@Indexed(index = "eu.etaxonomy.cdm.model.common.User")
73
@Audited
74
@Table(name = "UserAccount")
75
public class User extends CdmBase implements UserDetails {
76

    
77
    private static final long serialVersionUID = 6582191171369439163L;
78
    private static final Logger logger = LogManager.getLogger(User.class);
79

    
80
    public static final String USERNAME_REGEX = "[A-Za-z0-9_\\.\\-]+";
81

    
82
 // **************************** FACTORY *****************************************/
83

    
84
    public static User NewInstance(String username, String pwd){
85
        User user = new User();
86
        user.setUsername(username);
87
        user.setPassword(pwd);
88

    
89
        user.setAccountNonExpired(true);
90
        user.setAccountNonLocked(true);
91
        user.setCredentialsNonExpired(true);
92
        user.setEnabled(true);
93

    
94
        return user;
95
    }
96

    
97
    public static User NewInstance(String personTitle, String username, String pwd){
98
        User user = NewInstance(username, pwd);
99
        Person userPerson = Person.NewTitledInstance(personTitle);
100
        user.setPerson(userPerson);
101

    
102
        return user;
103
    }
104

    
105
//***************************** Fields *********************** /
106

    
107
    @XmlElement(name = "Username")
108
    @Column(unique = true)
109
    @Field(analyze = Analyze.NO)
110
    @NotNull
111
    @Pattern(regexp=USERNAME_REGEX)
112
    protected String username;
113

    
114
    /**
115
     * a salted, MD5 encoded hash of the plain text password
116
     */
117
    @XmlElement(name = "Password")
118
    @NotAudited
119
    @ValidPassword(groups=Level2.class)
120
    protected String password;
121

    
122

    
123
    /**
124
     * The salt for password hashing.
125
     * @see https://dev.e-taxonomy.eu/redmine/issues/7210
126
     * @see https://code-bude.net/2015/03/30/grundlagen-sicheres-passwort-hashing-mit-salts/
127
     */
128
    @XmlElement(name = "Salt")
129
    @NotAudited
130
    protected String salt;
131

    
132
    @XmlElement(name = "EmailAddress")
133
    protected String emailAddress;
134

    
135
    @XmlElementWrapper(name = "GrantedAuthorities")
136
    @XmlElement(name = "GrantedAuthority", type = GrantedAuthorityImpl.class)
137
    @XmlIDREF
138
    @XmlSchemaType(name = "IDREF")
139
    @ManyToMany(fetch = FetchType.LAZY, targetEntity = GrantedAuthorityImpl.class)
140
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE, CascadeType.REFRESH}) // see #2414 (Group updating doesn't work)
141
    @NotAudited
142
    protected Set<GrantedAuthority> grantedAuthorities = new HashSet<>();  //authorities of this user only
143

    
144
    @XmlElementWrapper(name = "Groups")
145
    @XmlElement(name = "Group")
146
    @XmlIDREF
147
    @XmlSchemaType(name = "IDREF")
148
    @ManyToMany(fetch = FetchType.LAZY)
149
    @IndexedEmbedded(depth = 1)
150
    @NotAudited
151
    protected Set<Group> groups = new HashSet<>();
152

    
153
    @XmlElement(name = "Enabled")
154
    protected boolean enabled;
155

    
156
    @XmlElement(name = "AccountNonExpired")
157
    protected boolean accountNonExpired;
158

    
159
    @XmlElement(name = "CredentialsNonExpired")
160
    protected boolean credentialsNonExpired;
161

    
162
    @XmlElement(name = "AccountNonLocked")
163
    protected boolean accountNonLocked;
164

    
165
    @XmlElement(name = "Person")
166
    @XmlIDREF
167
    @XmlSchemaType(name = "IDREF")
168
    @OneToOne(fetch = FetchType.LAZY)
169
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
170
    @IndexedEmbedded(depth = 1)
171
    protected Person person;
172

    
173
    @XmlTransient
174
    @Transient
175
    private Set<GrantedAuthority> transientGrantedAuthorities;  //authorities of this user and of all groups the user belongs to
176

    
177
    @XmlElementWrapper(name = "Authorities")
178
    @XmlElement(name = "Authority", type = AuthorityBase.class)
179
    @XmlIDREF
180
    @XmlSchemaType(name = "IDREF")
181
    @ManyToMany(fetch = FetchType.LAZY, targetEntity = AuthorityBase.class)
182
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
183
    @NotAudited
184
    protected Set<AuthorityBase> authorities = new HashSet<>();
185

    
186
    @XmlTransient
187
    @Transient
188
    private Set<AuthorityBase> transientAuthorities;  //authorities of this user and of all groups the user belongs to
189

    
190
//***************************** Constructor *********************** /
191

    
192
    protected User(){
193
        super();
194
    }
195

    
196
// ***************************** GETTER / SETTER ******************************/
197

    
198
    public Person getPerson() {return person;}
199
    public void setPerson(Person person) {this.person = person;}
200

    
201
    @Override
202
    public String getPassword() {return password;}
203
    public void setPassword(String password) {this.password = password;}
204

    
205
    @Override
206
    public String getUsername() {return username;}
207
    public void setUsername(String username) {this.username = username;}
208

    
209
    @Override
210
    public boolean isAccountNonLocked() {return accountNonLocked;}
211
    public void setAccountNonLocked(boolean accountNonLocked) {this.accountNonLocked = accountNonLocked;}
212

    
213
    @Override
214
    public boolean isCredentialsNonExpired() {return credentialsNonExpired;}
215
    public void setCredentialsNonExpired(boolean credentialsNonExpired) {this.credentialsNonExpired = credentialsNonExpired;}
216

    
217
    public String getEmailAddress() {return emailAddress;}
218
    public void setEmailAddress(String emailAddress) {this.emailAddress = emailAddress;}
219

    
220
    @Override
221
    public boolean isEnabled() {return enabled;}
222
    public void setEnabled(boolean enabled) {this.enabled = enabled;}
223

    
224
    @Override
225
    public boolean isAccountNonExpired() {return accountNonExpired;}
226
    public void setAccountNonExpired(boolean accountNonExpired) {this.accountNonExpired = accountNonExpired;}
227

    
228
    protected void setGroups(Set<Group> groups) {
229
        this.groups = groups;
230
        initAuthorities();
231
    }
232
    public Set<Group> getGroups() {return groups;}
233

    
234
    public Set<GrantedAuthority> getGrantedAuthorities() {return grantedAuthorities;}
235
    public void setGrantedAuthorities(Set<GrantedAuthority> grantedAuthorities) {
236
        this.grantedAuthorities = grantedAuthorities;
237
        initAuthorities();
238
    }
239

    
240
    public Set<AuthorityBase> getAuthoritiesB() {return authorities;}
241
    public void setAuthorities(Set<AuthorityBase> authorities) {
242
        this.authorities = authorities;
243
        initAuthorities();
244
    }
245
    public void addAuthority(AuthorityBase authority){
246
        this.authorities.add(authority);
247
        initAuthorities();
248
    }
249

    
250
// ************************** METHODS *********************/
251

    
252
    /**
253
     * Initializes or refreshes the collection of authorities, See
254
     * {@link #getAuthorities()}
255
     */
256
    //FIXME made public as preliminary solution to #4053 (Transient field User.authorities not refreshed on reloading entity)
257
    public void initAuthorities() {
258
        //GrantedAuthority
259
        transientGrantedAuthorities = new HashSet<>();
260
        transientGrantedAuthorities.addAll(grantedAuthorities);
261
        for(Group group : groups) {
262
            transientGrantedAuthorities.addAll(group.getGrantedAuthorities());
263
        }
264
        //CdmAuthority
265
        //TODO activating this currently leads to LIE in AuthenticationPresenterTest in Vaadin project
266
//        transientAuthorities = new HashSet<>();
267
//        transientAuthorities.addAll(authorities);
268
//        for(Group group : groups) {
269
//            transientAuthorities.addAll(group.getAuthorities());
270
//        }
271
    }
272

    
273
    /**
274
     * Implementation of {@link UserDetails#getAuthorities()}
275
     *
276
     * {@inheritDoc}
277
     *
278
     * @return returns all {@code Set<GrantedAuthority>} instances contained in
279
     *         the sets {@link #getGrantedAuthorities()} and
280
     *         {@link #getGroups()}
281
     */
282
    @Override
283
    @Transient
284
    public Collection<GrantedAuthority> getAuthorities() {
285
        if(transientGrantedAuthorities == null || transientGrantedAuthorities.size() == 0) {
286
            initAuthorities();
287
        }
288
        return transientGrantedAuthorities;
289
    }
290

    
291
    public static User getCurrentAuthenticatedUser() {
292
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
293
        if(authentication != null && authentication.getPrincipal() != null && authentication.getPrincipal() instanceof User) {
294
            return (User)authentication.getPrincipal();
295
        }
296
        return null;
297
    }
298

    
299
//*********************** CLONE ********************************************************/
300

    
301
    /**
302
     * Clones <i>this</i> User. This is a shortcut that enables to create
303
     * a new instance that differs only slightly from <i>this</i> User.
304
     * The corresponding person is cloned.
305
     *
306
     * @see eu.etaxonomy.cdm.model.common.CdmBase#clone()
307
     * @see java.lang.Object#clone()
308
     */
309
    @Override
310
    public User clone() {
311
        try{
312
            User result = (User)super.clone();
313
            if (this.person != null){
314
                result.setPerson(this.person.clone());
315
            }
316
            return result;
317
        } catch (CloneNotSupportedException e){
318
            logger.warn("Object does not implement cloneable");
319
            e.printStackTrace();
320
            return null;
321
        }
322
    }
323

    
324
//************************************** toString ***************************************
325

    
326
    @Override
327
    public String toString() {
328
        if (StringUtils.isNotBlank(username)){
329
            return username;
330
        }else{
331
            return super.toString();
332
        }
333
    }
334
}
(9-9/9)