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,11 +63,11 @@ | ||
63 | <artifactId>mysql-connector-java</artifactId> | 63 | <artifactId>mysql-connector-java</artifactId> |
64 | <version>${mysql-version}</version> | 64 | <version>${mysql-version}</version> |
65 | </dependency> | 65 | </dependency> |
66 | - <dependency> | 66 | + <!-- dependency> |
67 | <groupId>com.fasterxml.jackson.core</groupId> | 67 | <groupId>com.fasterxml.jackson.core</groupId> |
68 | <artifactId>jackson-databind</artifactId> | 68 | <artifactId>jackson-databind</artifactId> |
69 | <version>${jackson-version}</version> | 69 | <version>${jackson-version}</version> |
70 | - </dependency> | 70 | + </dependency --> |
71 | </dependencies> | 71 | </dependencies> |
72 | <build> | 72 | <build> |
73 | <finalName>swXercise</finalName> | 73 | <finalName>swXercise</finalName> |
src/main/java/net/ziemers/swxercise/db/dao/GenericDao.java
@@ -16,7 +16,7 @@ import net.ziemers.swxercise.db.BaseEntity; | @@ -16,7 +16,7 @@ import net.ziemers.swxercise.db.BaseEntity; | ||
16 | public class GenericDao { | 16 | public class GenericDao { |
17 | 17 | ||
18 | @PersistenceContext | 18 | @PersistenceContext |
19 | - private EntityManager entityManager; | 19 | + protected EntityManager entityManager; |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * Speichert die gegebene Entität. | 22 | * Speichert die gegebene Entität. |
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 | import javax.validation.constraints.NotNull; | 4 | import javax.validation.constraints.NotNull; |
7 | 5 | ||
8 | import net.ziemers.swxercise.db.BaseEntity; | 6 | import net.ziemers.swxercise.db.BaseEntity; |
9 | 7 | ||
10 | @Entity | 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 | public class User extends BaseEntity { | 12 | public class User extends BaseEntity { |
12 | 13 | ||
13 | private String firstname; | 14 | private String firstname; |
@@ -17,6 +18,8 @@ public class User extends BaseEntity { | @@ -17,6 +18,8 @@ public class User extends BaseEntity { | ||
17 | @NotNull | 18 | @NotNull |
18 | private Profile profile; | 19 | private Profile profile; |
19 | 20 | ||
21 | + private Address address; | ||
22 | + | ||
20 | public User() { | 23 | public User() { |
21 | super(); | 24 | super(); |
22 | } | 25 | } |
@@ -56,4 +59,13 @@ public class User extends BaseEntity { | @@ -56,4 +59,13 @@ public class User extends BaseEntity { | ||
56 | return this; | 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,20 +6,23 @@ import javax.ejb.Stateless; | ||
6 | import javax.inject.Inject; | 6 | import javax.inject.Inject; |
7 | 7 | ||
8 | import net.ziemers.swxercise.db.dao.GenericDao; | 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 | import net.ziemers.swxercise.lg.user.dto.UserDto; | 12 | import net.ziemers.swxercise.lg.user.dto.UserDto; |
12 | 13 | ||
13 | @Stateless | 14 | @Stateless |
14 | public class UserService { | 15 | public class UserService { |
15 | 16 | ||
16 | @Inject | 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 | public Collection<User> findAllUsers() { | 24 | public Collection<User> findAllUsers() { |
22 | - return genericDao.findAll(User.class); | 25 | + return dao.findAll(User.class); |
23 | } | 26 | } |
24 | 27 | ||
25 | public Long saveUser(final UserDto userDto) { | 28 | public Long saveUser(final UserDto userDto) { |
@@ -29,7 +32,7 @@ public class UserService { | @@ -29,7 +32,7 @@ public class UserService { | ||
29 | final User user = new User(userDto.getFirstname(), userDto.getLastname()) | 32 | final User user = new User(userDto.getFirstname(), userDto.getLastname()) |
30 | .withProfile(profile); | 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,8 +7,7 @@ import javax.inject.Inject; | ||
7 | import javax.ws.rs.*; | 7 | import javax.ws.rs.*; |
8 | import javax.ws.rs.core.MediaType; | 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 | import net.ziemers.swxercise.lg.user.dto.UserDto; | 11 | import net.ziemers.swxercise.lg.user.dto.UserDto; |
13 | import net.ziemers.swxercise.lg.user.service.UserService; | 12 | import net.ziemers.swxercise.lg.user.service.UserService; |
14 | 13 | ||
@@ -54,7 +53,6 @@ public class UserViewController { | @@ -54,7 +53,6 @@ public class UserViewController { | ||
54 | @Produces({MediaType.TEXT_PLAIN}) | 53 | @Produces({MediaType.TEXT_PLAIN}) |
55 | public String postUser(UserDto userDto) throws Exception { | 54 | public String postUser(UserDto userDto) throws Exception { |
56 | userService.saveUser(userDto); | 55 | userService.saveUser(userDto); |
57 | - | ||
58 | return "Ok"; | 56 | return "Ok"; |
59 | } | 57 | } |
60 | 58 |