Commit 2392615cebbd2a0429d07b2f66811b00a72f3145
1 parent
0bbe393d
feature: Profile ist feature-complete
Showing
11 changed files
with
251 additions
and
89 deletions
pom.xml
... | ... | @@ -63,11 +63,11 @@ |
63 | 63 | <artifactId>mysql-connector-java</artifactId> |
64 | 64 | <version>${mysql-version}</version> |
65 | 65 | </dependency> |
66 | - <dependency> | |
66 | + <!-- dependency> | |
67 | 67 | <groupId>com.fasterxml.jackson.core</groupId> |
68 | 68 | <artifactId>jackson-databind</artifactId> |
69 | 69 | <version>${jackson-version}</version> |
70 | - </dependency> | |
70 | + </dependency --> | |
71 | 71 | </dependencies> |
72 | 72 | <build> |
73 | 73 | <finalName>swXercise</finalName> | ... | ... |
src/main/java/net/ziemers/swxercise/db/dao/GenericDao.java
src/main/java/net/ziemers/swxercise/db/dao/user/UserDao.java
0 → 100644
1 | +package net.ziemers.swxercise.db.dao.user; | |
2 | + | |
3 | +import net.ziemers.swxercise.db.dao.GenericDao; | |
4 | +import net.ziemers.swxercise.lg.model.user.User; | |
5 | + | |
6 | +import javax.ejb.Stateless; | |
7 | + | |
8 | +@Stateless | |
9 | +public class UserDao extends GenericDao { | |
10 | + | |
11 | + public User findById(final Long id) { | |
12 | + User user = null; | |
13 | + | |
14 | + try { | |
15 | + // ermittelt den ersten Datensatz mit der gesuchten Id, auch wenn er sich nicht im Persistence Context befindet | |
16 | + user = (User) entityManager.createNamedQuery("User.findById").setParameter("id", id).getSingleResult(); | |
17 | + } catch(Exception e) { | |
18 | + /* nix */ | |
19 | + } | |
20 | + return user; | |
21 | + } | |
22 | + | |
23 | +} | ... | ... |
src/main/java/net/ziemers/swxercise/lg/user/Address.java renamed to src/main/java/net/ziemers/swxercise/lg/model/user/Address.java
src/main/java/net/ziemers/swxercise/lg/model/user/Profile.java
0 → 100644
1 | +package net.ziemers.swxercise.lg.model.user; | |
2 | + | |
3 | +import javax.persistence.Entity; | |
4 | +import javax.persistence.EnumType; | |
5 | +import javax.persistence.Enumerated; | |
6 | +import javax.validation.constraints.NotNull; | |
7 | +import javax.xml.bind.DatatypeConverter; | |
8 | + | |
9 | +import net.ziemers.swxercise.db.BaseEntity; | |
10 | +import net.ziemers.swxercise.lg.user.enums.PasswordHashAlgorithm; | |
11 | + | |
12 | +import java.security.MessageDigest; | |
13 | +import java.security.SecureRandom; | |
14 | +import java.util.Random; | |
15 | + | |
16 | +@Entity | |
17 | +public class Profile extends BaseEntity { | |
18 | + | |
19 | + @NotNull | |
20 | + private String username; | |
21 | + | |
22 | + @NotNull | |
23 | + private String passwordHash; | |
24 | + | |
25 | + @NotNull | |
26 | + private PasswordHashAlgorithm hashAlgorithm = PasswordHashAlgorithm.SHA512; | |
27 | + | |
28 | + @NotNull | |
29 | + private String salt; | |
30 | + | |
31 | + private String mailaddress; | |
32 | + | |
33 | + /* | |
34 | + * ***************************************************************************************************************************** | |
35 | + * Konstruktoren | |
36 | + * ***************************************************************************************************************************** | |
37 | + */ | |
38 | + | |
39 | + public Profile() { | |
40 | + super(); | |
41 | + | |
42 | + setSalt(this.generateSalt()); | |
43 | + } | |
44 | + | |
45 | + public Profile(final String username, final String password) { | |
46 | + this(); | |
47 | + | |
48 | + setUsername(username); | |
49 | + setPasswordHash(password); | |
50 | + } | |
51 | + | |
52 | + /* | |
53 | + * ***************************************************************************************************************************** | |
54 | + * Methoden | |
55 | + * ***************************************************************************************************************************** | |
56 | + */ | |
57 | + | |
58 | + private byte[] base64ToByte(final String str) { | |
59 | + byte[] bytes; | |
60 | + // Java 6 ships the javax.xml.bind.DatatypeConverter this class provides two static methods that support the same decoding & | |
61 | + // encoding: parseBase64Binary() and printBase64Binary(). Use this and you will not need an extra library, like Apache | |
62 | + // Commons Codec. | |
63 | + // BASE64Decoder decoder = new BASE64Decoder(); | |
64 | + | |
65 | + // try { | |
66 | + // bytes = decoder.decodeBuffer(str); | |
67 | + bytes = DatatypeConverter.parseBase64Binary(str); | |
68 | + // } catch(IOException e) { | |
69 | + // e.printStackTrace(); | |
70 | + // } | |
71 | + return bytes; | |
72 | + } | |
73 | + private String byteToBase64(final byte[] bytes) { | |
74 | + // Java 6 ships the javax.xml.bind.DatatypeConverter this class provides two static methods that support the same decoding & | |
75 | + // encoding: parseBase64Binary() and printBase64Binary(). Use this and you will not need an extra library, like Apache | |
76 | + // Commons Codec. | |
77 | + // BASE64Encoder encoder = new BASE64Encoder(); | |
78 | + | |
79 | + // String str = encoder.encode(bytes); | |
80 | + String str = DatatypeConverter.printBase64Binary(bytes); | |
81 | + return str; | |
82 | + } | |
83 | + | |
84 | + private String cryptString(String string) { | |
85 | + final int HASH_ITERATION_COUNT = 5; | |
86 | + | |
87 | + String hashedString = ""; | |
88 | + | |
89 | + // vor dem Verschlüsseln den benutzerspezifischen Salt an das Kennwort anhängen | |
90 | + string += this.getSalt(); | |
91 | + | |
92 | + // Quelle: http://codeschnipsel.wordpress.com/2008/11/13/passwort-hash-in-java/ | |
93 | + MessageDigest md; | |
94 | + try { | |
95 | + md = MessageDigest.getInstance(getHashAlgorithm().getAlgorithm()); | |
96 | + md.reset(); | |
97 | + md.update(base64ToByte(this.getSalt())); | |
98 | + | |
99 | + byte[] bytes = md.digest(string.getBytes("UTF-8")); | |
100 | + for(int i = 0; i < HASH_ITERATION_COUNT; i++) { | |
101 | + md.reset(); | |
102 | + bytes = md.digest(bytes); | |
103 | + } | |
104 | + hashedString = byteToBase64(bytes); | |
105 | + } catch(Exception e) { | |
106 | + e.printStackTrace(); | |
107 | + } | |
108 | + return hashedString; | |
109 | + } | |
110 | + | |
111 | + private String generateSalt() { | |
112 | + final int HASH_LENGTH = 20; // Ferguson & Schneier overcautiously recommend 32 | |
113 | + | |
114 | + // Quelle: http://www.javamex.com/tutorials/cryptography/pbe_salt.shtml | |
115 | + Random random = new SecureRandom(); | |
116 | + byte[] salt = new byte[HASH_LENGTH]; | |
117 | + | |
118 | + random.nextBytes(salt); | |
119 | + return byteToBase64(salt); | |
120 | + } | |
121 | + | |
122 | + /* | |
123 | + * ***************************************************************************************************************************** | |
124 | + * Getters und Setters | |
125 | + * ***************************************************************************************************************************** | |
126 | + */ | |
127 | + | |
128 | + public String getUsername() { | |
129 | + return username; | |
130 | + } | |
131 | + | |
132 | + public void setUsername(String username) { | |
133 | + this.username = username; | |
134 | + } | |
135 | + | |
136 | + // da die Methode "private" ist, wird der Kennwort-Hashwert niemals per REST in einem JSON-Objekt übermittelt | |
137 | + private String getPasswordHash() { | |
138 | + return passwordHash; | |
139 | + } | |
140 | + | |
141 | + private void setPasswordHash(String password) { | |
142 | + // das Klartextkennwort wird niemals gespeichert! | |
143 | + this.passwordHash = cryptString(password); | |
144 | + } | |
145 | + | |
146 | + public boolean isValidPassword(final String password) { | |
147 | + return getPasswordHash().equals(cryptString(password)); | |
148 | + } | |
149 | + | |
150 | + @Enumerated(EnumType.STRING) | |
151 | + private PasswordHashAlgorithm getHashAlgorithm() { | |
152 | + return hashAlgorithm; | |
153 | + } | |
154 | + | |
155 | + private void setHashAlgorithm(PasswordHashAlgorithm hashAlgorithm) { | |
156 | + this.hashAlgorithm = hashAlgorithm; | |
157 | + } | |
158 | + | |
159 | + // da die Methode "private" ist, wird der Kennwort-Saltwert niemals per REST in einem JSON-Objekt übermittelt | |
160 | + private String getSalt() { | |
161 | + return salt; | |
162 | + } | |
163 | + | |
164 | + private void setSalt(String salt) { | |
165 | + this.salt = salt; | |
166 | + } | |
167 | + | |
168 | + public String getMailaddress() { | |
169 | + return mailaddress; | |
170 | + } | |
171 | + | |
172 | + public void setMailaddress(String mailaddress) { | |
173 | + this.mailaddress = mailaddress; | |
174 | + } | |
175 | + | |
176 | +} | ... | ... |
src/main/java/net/ziemers/swxercise/lg/user/User.java renamed to src/main/java/net/ziemers/swxercise/lg/model/user/User.java
1 | -package net.ziemers.swxercise.lg.user; | |
1 | +package net.ziemers.swxercise.lg.model.user; | |
2 | 2 | |
3 | -import javax.persistence.CascadeType; | |
4 | -import javax.persistence.Entity; | |
5 | -import javax.persistence.OneToOne; | |
3 | +import javax.persistence.*; | |
6 | 4 | import javax.validation.constraints.NotNull; |
7 | 5 | |
8 | 6 | import net.ziemers.swxercise.db.BaseEntity; |
9 | 7 | |
10 | 8 | @Entity |
9 | +@NamedQueries({ | |
10 | + @NamedQuery(name = "User.findById", query = "SELECT u FROM User u WHERE u.id = :id"), | |
11 | + @NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")}) | |
11 | 12 | public class User extends BaseEntity { |
12 | 13 | |
13 | 14 | private String firstname; |
... | ... | @@ -17,6 +18,8 @@ public class User extends BaseEntity { |
17 | 18 | @NotNull |
18 | 19 | private Profile profile; |
19 | 20 | |
21 | + private Address address; | |
22 | + | |
20 | 23 | public User() { |
21 | 24 | super(); |
22 | 25 | } |
... | ... | @@ -56,4 +59,13 @@ public class User extends BaseEntity { |
56 | 59 | return this; |
57 | 60 | } |
58 | 61 | |
62 | + @OneToOne(cascade = {CascadeType.ALL}) | |
63 | + public Address getAddress() { | |
64 | + return address; | |
65 | + } | |
66 | + | |
67 | + public void setAddress(Address address) { | |
68 | + this.address = address; | |
69 | + } | |
70 | + | |
59 | 71 | } | ... | ... |
src/main/java/net/ziemers/swxercise/lg/user/Profile.java deleted
100644 → 0
1 | -package net.ziemers.swxercise.lg.user; | |
2 | - | |
3 | -import javax.persistence.Entity; | |
4 | -import javax.validation.constraints.NotNull; | |
5 | - | |
6 | -import net.ziemers.swxercise.db.BaseEntity; | |
7 | -import net.ziemers.swxercise.lg.user.enums.PasswordHashType; | |
8 | - | |
9 | -@Entity | |
10 | -public class Profile extends BaseEntity { | |
11 | - | |
12 | - @NotNull | |
13 | - private String username; | |
14 | - | |
15 | - @NotNull | |
16 | - private String passwordHash; | |
17 | - | |
18 | - @NotNull | |
19 | - private PasswordHashType passwordHashType = PasswordHashType.Unknown; | |
20 | - | |
21 | - private String mailaddress; | |
22 | - | |
23 | - public Profile() { | |
24 | - super(); | |
25 | - } | |
26 | - | |
27 | - public Profile(final String username, final String password) { | |
28 | - this.username = username; | |
29 | - // TODO Kennwort verhashen | |
30 | - this.passwordHash = password; | |
31 | - } | |
32 | - | |
33 | - public String getUsername() { | |
34 | - return username; | |
35 | - } | |
36 | - | |
37 | - public void setUsername(String username) { | |
38 | - this.username = username; | |
39 | - } | |
40 | - | |
41 | - private String getPasswordHash() { | |
42 | - return passwordHash; | |
43 | - } | |
44 | - | |
45 | - private void setPasswordHash(String passwordHash) { | |
46 | - this.passwordHash = passwordHash; | |
47 | - } | |
48 | - | |
49 | - private PasswordHashType getPasswordHashType() { | |
50 | - return passwordHashType; | |
51 | - } | |
52 | - | |
53 | - private void setPasswordHashType(PasswordHashType passwordHashType) { | |
54 | - this.passwordHashType = passwordHashType; | |
55 | - } | |
56 | - | |
57 | - public String getMailaddress() { | |
58 | - return mailaddress; | |
59 | - } | |
60 | - | |
61 | - public void setMailaddress(String mailaddress) { | |
62 | - this.mailaddress = mailaddress; | |
63 | - } | |
64 | - | |
65 | -} |
src/main/java/net/ziemers/swxercise/lg/user/enums/PasswordHashAlgorithm.java
0 → 100644
1 | +package net.ziemers.swxercise.lg.user.enums; | |
2 | + | |
3 | +public enum PasswordHashAlgorithm { | |
4 | + | |
5 | + SHA512("SHA-512"), | |
6 | + ; | |
7 | + | |
8 | + private String algorithm; | |
9 | + | |
10 | + PasswordHashAlgorithm(final String algorithm) { | |
11 | + setAlgorithm(algorithm); | |
12 | + } | |
13 | + | |
14 | + public String getAlgorithm() { | |
15 | + return algorithm; | |
16 | + } | |
17 | + | |
18 | + private void setAlgorithm(String algorithm) { | |
19 | + this.algorithm = algorithm; | |
20 | + } | |
21 | + | |
22 | +} | ... | ... |
src/main/java/net/ziemers/swxercise/lg/user/enums/PasswordHashType.java deleted
100644 → 0
src/main/java/net/ziemers/swxercise/lg/user/service/UserService.java
... | ... | @@ -6,20 +6,23 @@ import javax.ejb.Stateless; |
6 | 6 | import javax.inject.Inject; |
7 | 7 | |
8 | 8 | import net.ziemers.swxercise.db.dao.GenericDao; |
9 | -import net.ziemers.swxercise.lg.user.Profile; | |
10 | -import net.ziemers.swxercise.lg.user.User; | |
9 | +import net.ziemers.swxercise.db.dao.user.UserDao; | |
10 | +import net.ziemers.swxercise.lg.model.user.Profile; | |
11 | +import net.ziemers.swxercise.lg.model.user.User; | |
11 | 12 | import net.ziemers.swxercise.lg.user.dto.UserDto; |
12 | 13 | |
13 | 14 | @Stateless |
14 | 15 | public class UserService { |
15 | 16 | |
16 | 17 | @Inject |
17 | - private GenericDao genericDao; | |
18 | + private UserDao dao; | |
18 | 19 | |
19 | - public User findUser(final Long id) { return genericDao.findById(User.class, id); } | |
20 | + public User findUser(final Long id) { | |
21 | + return dao.findById(id); | |
22 | + } | |
20 | 23 | |
21 | 24 | public Collection<User> findAllUsers() { |
22 | - return genericDao.findAll(User.class); | |
25 | + return dao.findAll(User.class); | |
23 | 26 | } |
24 | 27 | |
25 | 28 | public Long saveUser(final UserDto userDto) { |
... | ... | @@ -29,7 +32,7 @@ public class UserService { |
29 | 32 | final User user = new User(userDto.getFirstname(), userDto.getLastname()) |
30 | 33 | .withProfile(profile); |
31 | 34 | |
32 | - return genericDao.save(user); | |
35 | + return dao.save(user); | |
33 | 36 | } |
34 | 37 | |
35 | 38 | } | ... | ... |
src/main/java/net/ziemers/swxercise/ui/UserViewController.java
... | ... | @@ -7,8 +7,7 @@ import javax.inject.Inject; |
7 | 7 | import javax.ws.rs.*; |
8 | 8 | import javax.ws.rs.core.MediaType; |
9 | 9 | |
10 | -import net.ziemers.swxercise.lg.user.Profile; | |
11 | -import net.ziemers.swxercise.lg.user.User; | |
10 | +import net.ziemers.swxercise.lg.model.user.User; | |
12 | 11 | import net.ziemers.swxercise.lg.user.dto.UserDto; |
13 | 12 | import net.ziemers.swxercise.lg.user.service.UserService; |
14 | 13 | |
... | ... | @@ -54,7 +53,6 @@ public class UserViewController { |
54 | 53 | @Produces({MediaType.TEXT_PLAIN}) |
55 | 54 | public String postUser(UserDto userDto) throws Exception { |
56 | 55 | userService.saveUser(userDto); |
57 | - | |
58 | 56 | return "Ok"; |
59 | 57 | } |
60 | 58 | ... | ... |