blob: b42039934724dcfade60799187b3328fd474662c [file] [log] [blame]
margaretha139d0f72017-11-14 18:56:22 +01001package de.ids_mannheim.korap.authentication;
Michael Hanl87106d12015-09-14 18:13:51 +02002
margarethaebc54962017-05-29 13:23:07 +02003import java.io.IOException;
4import java.io.UnsupportedEncodingException;
5import java.net.InetAddress;
6import java.net.UnknownHostException;
7import java.security.NoSuchAlgorithmException;
8import java.util.Collection;
9import java.util.Map;
Bodmo11fb6f82017-06-01 11:39:15 +020010import java.util.Arrays;
margarethaebc54962017-05-29 13:23:07 +020011
12import javax.ws.rs.core.HttpHeaders;
13import javax.ws.rs.core.MultivaluedMap;
14
15import org.slf4j.Logger;
16import org.slf4j.LoggerFactory;
17
18// import com.novell.ldap.*; search() funktioniert nicht korrekt, ausgewechselt gegen unboundID's Bibliothek 20.04.17/FB
19//Using JAR from unboundID:
20import com.unboundid.ldap.sdk.LDAPException;
Bodmoca3dcfb2017-05-24 16:36:00 +020021
Michael Hanl87106d12015-09-14 18:13:51 +020022import de.ids_mannheim.korap.auditing.AuditRecord;
Michael Hanl00b64e02016-05-24 20:24:27 +020023import de.ids_mannheim.korap.config.Attributes;
margaretha139d0f72017-11-14 18:56:22 +010024import de.ids_mannheim.korap.config.AuthenticationType;
Michael Hanldaf86602016-05-12 14:31:52 +020025import de.ids_mannheim.korap.config.BeansFactory;
Michael Hanl87106d12015-09-14 18:13:51 +020026import de.ids_mannheim.korap.config.KustvaktConfiguration;
27import de.ids_mannheim.korap.config.URIParam;
margarethaebc54962017-05-29 13:23:07 +020028import de.ids_mannheim.korap.exceptions.EmptyResultException;
29import de.ids_mannheim.korap.exceptions.KustvaktException;
30import de.ids_mannheim.korap.exceptions.NotAuthorizedException;
31import de.ids_mannheim.korap.exceptions.StatusCodes;
32import de.ids_mannheim.korap.exceptions.WrappedException;
Michael Hanl19390652016-01-16 11:01:24 +010033import de.ids_mannheim.korap.interfaces.AuthenticationIface;
34import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
35import de.ids_mannheim.korap.interfaces.EncryptionIface;
Michael Hanlc0ed00f2016-06-23 14:33:10 +020036import de.ids_mannheim.korap.interfaces.ValidatorIface;
margaretha62055f72017-04-11 19:17:43 +020037import de.ids_mannheim.korap.interfaces.db.AdminHandlerIface;
Michael Hanlf21773f2015-10-16 23:02:31 +020038import de.ids_mannheim.korap.interfaces.db.AuditingIface;
39import de.ids_mannheim.korap.interfaces.db.EntityHandlerIface;
Michael Hanl415276b2016-01-29 16:39:37 +010040import de.ids_mannheim.korap.interfaces.db.UserDataDbIface;
Michael Hanlc0ed00f2016-06-23 14:33:10 +020041import de.ids_mannheim.korap.interfaces.defaults.ApacheValidator;
margarethaebc54962017-05-29 13:23:07 +020042import de.ids_mannheim.korap.user.DemoUser;
43import de.ids_mannheim.korap.user.KorAPUser;
44import de.ids_mannheim.korap.user.ShibUser;
45import de.ids_mannheim.korap.user.TokenContext;
46import de.ids_mannheim.korap.user.User;
Bodmoca3dcfb2017-05-24 16:36:00 +020047import de.ids_mannheim.korap.user.User.CorpusAccess;
margarethaebc54962017-05-29 13:23:07 +020048import de.ids_mannheim.korap.user.User.Location;
49import de.ids_mannheim.korap.user.UserDetails;
50import de.ids_mannheim.korap.user.UserSettings;
51import de.ids_mannheim.korap.user.Userdata;
Michael Hanlcb2d3f92016-06-02 17:34:06 +020052import de.ids_mannheim.korap.utils.StringUtils;
Michael Hanl87106d12015-09-14 18:13:51 +020053import de.ids_mannheim.korap.utils.TimeUtils;
Bodmoca3dcfb2017-05-24 16:36:00 +020054
Michael Hanl87106d12015-09-14 18:13:51 +020055/**
margarethaebc54962017-05-29 13:23:07 +020056 * contains the logic to authentication and registration processes. Uses
57 * interface implementations (AuthenticationIface) for different databases and
58 * handlers
Michael Hanl8abaf9e2016-05-23 16:46:35 +020059 *
Michael Hanl87106d12015-09-14 18:13:51 +020060 * @author hanl
61 */
62public class KustvaktAuthenticationManager extends AuthenticationManagerIface {
63
margarethaebc54962017-05-29 13:23:07 +020064 private static Logger jlog = LoggerFactory.getLogger(KustvaktAuthenticationManager.class);
65 private EncryptionIface crypto;
66 private EntityHandlerIface entHandler;
67 private AdminHandlerIface adminHandler;
68 private AuditingIface auditing;
69 private KustvaktConfiguration config;
70 private Collection userdatadaos;
71 private LoginCounter counter;
72 private ValidatorIface validator;
Michael Hanl8abaf9e2016-05-23 16:46:35 +020073
margarethaebc54962017-05-29 13:23:07 +020074 public KustvaktAuthenticationManager(EntityHandlerIface userdb, AdminHandlerIface admindb, EncryptionIface crypto,
75 KustvaktConfiguration config, AuditingIface auditer, Collection<UserDataDbIface> userdatadaos) {
76 this.entHandler = userdb;
77 this.adminHandler = admindb;
78 this.config = config;
79 this.crypto = crypto;
80 this.auditing = auditer;
81 this.counter = new LoginCounter(config);
82 this.userdatadaos = userdatadaos;
83 // todo: load via beancontext
84 try {
85 this.validator = new ApacheValidator();
86 } catch (IOException e) {
87 e.printStackTrace();
88 }
89 }
Michael Hanl87106d12015-09-14 18:13:51 +020090
margarethaebc54962017-05-29 13:23:07 +020091 /**
92 * get session object if token was a session token
93 *
94 * @param token
95 * @param host
96 * @param useragent
97 * @return
98 * @throws KustvaktException
99 */
100 @Override
101 public TokenContext getTokenStatus(String token, String host, String useragent) throws KustvaktException {
102 if (token == null)
103 throw new KustvaktException(StatusCodes.MISSING_ARGUMENT, "authorization header");
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200104
margarethaebc54962017-05-29 13:23:07 +0200105 String token_type = StringUtils.getTokenType(token);
106 token = StringUtils.stripTokenType(token);
107 jlog.info("getting session status of token type '{}'", token.split(" ")[0]);
108 AuthenticationIface provider = getProvider(token_type, null);
Michael Hanl99cb9632016-06-29 16:24:40 +0200109
margarethaebc54962017-05-29 13:23:07 +0200110 if (provider == null)
111 // throw exception for missing type parameter
112 throw new KustvaktException(StatusCodes.ILLEGAL_ARGUMENT, "token type not defined or found", "token_type");
Michael Hanl19390652016-01-16 11:01:24 +0100113
margarethaebc54962017-05-29 13:23:07 +0200114 TokenContext context = provider.getTokenContext(token);
115 if (context != null && TimeUtils.isExpired(context.getExpirationTime()))
116 throw new KustvaktException(StatusCodes.EXPIRED);
117 else if (context == null)
margarethaf6d5a822017-10-19 19:51:20 +0200118 throw new KustvaktException(StatusCodes.NO_RESULT_FOUND);
Michael Hanl19390652016-01-16 11:01:24 +0100119
margarethaebc54962017-05-29 13:23:07 +0200120 // if (!matchStatus(host, useragent, context))
121 // provider.removeUserSession(token);
122 return context;
123 }
Michael Hanlc0ed00f2016-06-23 14:33:10 +0200124
margarethaebc54962017-05-29 13:23:07 +0200125 @Override
126 public User getUser(String username) throws KustvaktException {
127 // User user;
128 // Object value = this.getCacheValue(username);
Michael Hanl87106d12015-09-14 18:13:51 +0200129
margarethaebc54962017-05-29 13:23:07 +0200130 if (User.UserFactory.isDemo(username))
131 return User.UserFactory.getDemoUser();
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200132
margarethaebc54962017-05-29 13:23:07 +0200133 // if (value != null) {
134 // Map map = (Map) value;
135 // user = User.UserFactory.toUser(map);
136 // }
137 // else {
138 // user = entHandler.getAccount(username);
139 // this.storeInCache(username, user.toCache());
140 // todo: not valid. for the duration of the session, the host should not
141 // change!
142 // }
143 // todo:
144 // user.addField(Attributes.HOST, context.getHostAddress());
145 // user.addField(Attributes.USER_AGENT, context.getUserAgent());
146 return entHandler.getAccount(username);
147 }
Michael Hanl87106d12015-09-14 18:13:51 +0200148
margarethaebc54962017-05-29 13:23:07 +0200149 public TokenContext refresh(TokenContext context) throws KustvaktException {
150 AuthenticationIface provider = getProvider(context.getTokenType(), null);
151 if (provider == null) {
152 // todo:
153 }
Michael Hanlc4446022016-02-12 18:03:17 +0100154
margarethaebc54962017-05-29 13:23:07 +0200155 try {
156 provider.removeUserSession(context.getToken());
157 User user = getUser(context.getUsername());
158 return provider.createTokenContext(user, context.params());
159 } catch (KustvaktException e) {
160 throw new WrappedException(e, StatusCodes.LOGIN_FAILED);
161 }
162 }
Michael Hanl87106d12015-09-14 18:13:51 +0200163
margarethafde771a2017-11-14 15:02:10 +0100164 /** EM: fix type is not flexible
margarethaebc54962017-05-29 13:23:07 +0200165 * @param type
166 * @param attributes
167 * contains username and password to authenticate the user.
168 * Depending of the authentication schema, may contain other
169 * values as well
170 * @return User
171 * @throws KustvaktException
172 */
173 @Override
margaretha139d0f72017-11-14 18:56:22 +0100174 public User authenticate(AuthenticationType type, String username, String password, Map<String, Object> attributes)
margarethaebc54962017-05-29 13:23:07 +0200175 throws KustvaktException {
176 User user;
177 switch (type) {
margaretha139d0f72017-11-14 18:56:22 +0100178 case SHIBBOLETH:
margarethaebc54962017-05-29 13:23:07 +0200179 // todo:
180 user = authenticateShib(attributes);
181 break;
margaretha139d0f72017-11-14 18:56:22 +0100182 case LDAP:
margarethaebc54962017-05-29 13:23:07 +0200183 // IdM/LDAP: (09.02.17/FB)
184 user = authenticateIdM(username, password, attributes);
185 break;
186 default:
187 user = authenticate(username, password, attributes);
188 break;
189 }
190 auditing.audit(AuditRecord.serviceRecord(user.getId(), StatusCodes.LOGIN_SUCCESSFUL, user.toString()));
191 return user;
192 }
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200193
margarethaebc54962017-05-29 13:23:07 +0200194 // a. set location depending on X-Forwarded-For.
195 // X-Forwarded-For: clientIP, ProxyID, ProxyID...
196 // the following private address spaces may be used to define intranet
197 // spaces:
198 // 10.0.0.0 - 10.255.255.255 (10/8 prefix)
199 // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
200 // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
201 // b. set corpusAccess depending on location:
Bodmo11fb6f82017-06-01 11:39:15 +0200202 // c. DemoUser only gets corpusAccess=FREE.
margarethaebc54962017-05-29 13:23:07 +0200203 // 16.05.17/FB
Michael Hanlc0ed00f2016-06-23 14:33:10 +0200204
margarethaebc54962017-05-29 13:23:07 +0200205 @Override
206 public void setAccessAndLocation(User user, HttpHeaders headers) {
207 Boolean DEBUG_LOG = true;
208 MultivaluedMap<String, String> headerMap = headers.getRequestHeaders();
209 Location location = Location.EXTERN;
210 CorpusAccess corpusAccess = CorpusAccess.FREE;
margarethaa89c3f92017-05-30 19:02:08 +0200211
Bodmo11fb6f82017-06-01 11:39:15 +0200212 if( user instanceof DemoUser )
213 {
214 // to be absolutely sure:
215 user.setCorpusAccess(User.CorpusAccess.FREE);
216 if( DEBUG_LOG == true )
Bodmoc125bf12017-06-01 16:23:59 +0200217 System.out.printf("setAccessAndLocation: DemoUser: location=%s, access=%s.\n", user.locationtoString(), user.accesstoString());
Bodmo11fb6f82017-06-01 11:39:15 +0200218 return;
219 }
margarethaa89c3f92017-05-30 19:02:08 +0200220
margarethaebc54962017-05-29 13:23:07 +0200221 if (headerMap != null && headerMap.containsKey(org.eclipse.jetty.http.HttpHeaders.X_FORWARDED_FOR)) {
Michael Hanl87106d12015-09-14 18:13:51 +0200222
margarethaebc54962017-05-29 13:23:07 +0200223 String[] vals = headerMap.getFirst(org.eclipse.jetty.http.HttpHeaders.X_FORWARDED_FOR).split(",");
224 String clientAddress = vals[0];
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200225
margarethaebc54962017-05-29 13:23:07 +0200226 try {
227 InetAddress ip = InetAddress.getByName(clientAddress);
228 if (ip.isSiteLocalAddress()){
margarethaebc54962017-05-29 13:23:07 +0200229 location = Location.INTERN;
margarethaebc54962017-05-29 13:23:07 +0200230 corpusAccess = CorpusAccess.ALL;
231 }
margarethaa89c3f92017-05-30 19:02:08 +0200232 else{
233 corpusAccess = CorpusAccess.PUB;
234 }
235
margarethaebc54962017-05-29 13:23:07 +0200236 if (DEBUG_LOG == true) {
Bodmo11fb6f82017-06-01 11:39:15 +0200237 System.out.printf("Debug: X-Forwarded-For : '%s' (%d values) -> %s\n",
238 Arrays.toString(vals), vals.length, vals[0]);
margarethaebc54962017-05-29 13:23:07 +0200239 System.out.printf("Debug: X-Forwarded-For : location = %s corpusAccess = %s\n",
240 location == Location.INTERN ? "INTERN" : "EXTERN", corpusAccess == CorpusAccess.ALL ? "ALL"
241 : corpusAccess == CorpusAccess.PUB ? "PUB" : "FREE");
242 }
Michael Hanl87106d12015-09-14 18:13:51 +0200243
margarethaebc54962017-05-29 13:23:07 +0200244 } catch (UnknownHostException e) {
245 // TODO Auto-generated catch block
246 e.printStackTrace();
247 }
Michael Hanl87106d12015-09-14 18:13:51 +0200248
margarethaebc54962017-05-29 13:23:07 +0200249 user.setLocation(location);
250 user.setCorpusAccess(corpusAccess);
Bodmoc125bf12017-06-01 16:23:59 +0200251 if( DEBUG_LOG == true )
252 System.out.printf("setAccessAndLocation: KorAPUser: location=%s, access=%s.\n", user.locationtoString(), user.accesstoString());
253
margarethaebc54962017-05-29 13:23:07 +0200254 }
255 } // getAccess
Michael Hanl87106d12015-09-14 18:13:51 +0200256
margarethaebc54962017-05-29 13:23:07 +0200257 @Override
258 public TokenContext createTokenContext(User user, Map<String, Object> attr, String provider_key)
259 throws KustvaktException {
260 AuthenticationIface provider = getProvider(provider_key, Attributes.API_AUTHENTICATION);
Michael Hanl87106d12015-09-14 18:13:51 +0200261
margaretha38d530e2017-07-11 19:06:50 +0200262 // EM: not in the new DB
263// if (attr.get(Attributes.SCOPES) != null)
264// this.getUserData(user, UserDetails.class);
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200265
margarethaebc54962017-05-29 13:23:07 +0200266 TokenContext context = provider.createTokenContext(user, attr);
267 if (context == null)
268 throw new KustvaktException(StatusCodes.NOT_SUPPORTED);
269 context.setUserAgent((String) attr.get(Attributes.USER_AGENT));
270 context.setHostAddress(Attributes.HOST);
271 return context;
272 }
Michael Hanl87106d12015-09-14 18:13:51 +0200273
margarethaebc54962017-05-29 13:23:07 +0200274 // todo: test
275 @Deprecated
276 private boolean matchStatus(String host, String useragent, TokenContext context) {
277 if (host.equals(context.getHostAddress())) {
278 if (useragent.equals(context.getUserAgent()))
279 return true;
280 }
281 return false;
282 }
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200283
margarethaebc54962017-05-29 13:23:07 +0200284 private User authenticateShib(Map<String, Object> attributes) throws KustvaktException {
285 // todo use persistent id, since eppn is not unique
286 String eppn = (String) attributes.get(Attributes.EPPN);
Michael Hanl87106d12015-09-14 18:13:51 +0200287
margarethaebc54962017-05-29 13:23:07 +0200288 if (eppn == null || eppn.isEmpty())
289 throw new KustvaktException(StatusCodes.REQUEST_INVALID);
Michael Hanl87106d12015-09-14 18:13:51 +0200290
margarethaebc54962017-05-29 13:23:07 +0200291 if (!attributes.containsKey(Attributes.EMAIL) && validator.isValid(eppn, Attributes.EMAIL))
292 attributes.put(Attributes.EMAIL, eppn);
Michael Hanl87106d12015-09-14 18:13:51 +0200293
margarethaebc54962017-05-29 13:23:07 +0200294 User user = null;
295 if (isRegistered(eppn))
296 user = createShibbUserAccount(attributes);
297 return user;
298 }
Michael Hanl87106d12015-09-14 18:13:51 +0200299
margarethaebc54962017-05-29 13:23:07 +0200300 // todo: what if attributes null?
301 private User authenticate(String username, String password, Map<String, Object> attr) throws KustvaktException {
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200302
margarethaebc54962017-05-29 13:23:07 +0200303 Map<String, Object> attributes = validator.validateMap(attr);
304 User unknown;
305 // just to make sure that the plain password does not appear anywhere in
306 // the logs!
Michael Hanl87106d12015-09-14 18:13:51 +0200307
margarethaebc54962017-05-29 13:23:07 +0200308 try {
309 validator.validateEntry(username, Attributes.USERNAME);
310 } catch (KustvaktException e) {
311 throw new WrappedException(e, StatusCodes.LOGIN_FAILED, username);
312 }
Michael Hanl87106d12015-09-14 18:13:51 +0200313
margarethaebc54962017-05-29 13:23:07 +0200314 if (username == null || username.isEmpty())
315 throw new WrappedException(new KustvaktException(username, StatusCodes.BAD_CREDENTIALS),
316 StatusCodes.LOGIN_FAILED);
317 else {
318 try {
319 unknown = entHandler.getAccount(username);
320 } catch (EmptyResultException e) {
321 // mask exception to disable user guessing in possible attacks
322 throw new WrappedException(new KustvaktException(username, StatusCodes.BAD_CREDENTIALS),
323 StatusCodes.LOGIN_FAILED, username);
324 } catch (KustvaktException e) {
325 jlog.error("Error: {}", e);
326 throw new WrappedException(e, StatusCodes.LOGIN_FAILED, attributes.toString());
327 }
328 }
Michael Hanl87106d12015-09-14 18:13:51 +0200329
margarethaebc54962017-05-29 13:23:07 +0200330 boolean isAdmin = adminHandler.isAdmin(unknown.getId());
331 unknown.setAdmin(isAdmin);
margarethaf18298b2017-09-14 22:14:32 +0200332 jlog.debug("Authentication: found username " + unknown.getUsername());
Michael Hanl87106d12015-09-14 18:13:51 +0200333
margarethaebc54962017-05-29 13:23:07 +0200334 if (unknown instanceof KorAPUser) {
335 if (password == null || password.isEmpty())
336 throw new WrappedException(new KustvaktException(unknown.getId(), StatusCodes.BAD_CREDENTIALS),
337 StatusCodes.LOGIN_FAILED, username);
Michael Hanl87106d12015-09-14 18:13:51 +0200338
margarethaebc54962017-05-29 13:23:07 +0200339 KorAPUser user = (KorAPUser) unknown;
340 boolean check = crypto.checkHash(password, user.getPassword());
Michael Hanl87106d12015-09-14 18:13:51 +0200341
margarethaebc54962017-05-29 13:23:07 +0200342 if (!check) {
343 // the fail counter only applies for wrong password
344 jlog.warn("Wrong Password!");
345 processLoginFail(unknown);
346 throw new WrappedException(new KustvaktException(user.getId(), StatusCodes.BAD_CREDENTIALS),
347 StatusCodes.LOGIN_FAILED, username);
348 }
Michael Hanl87106d12015-09-14 18:13:51 +0200349
margarethaebc54962017-05-29 13:23:07 +0200350 // bad credentials error has precedence over account locked or
351 // unconfirmed codes
352 // since latter can lead to account guessing of third parties
353 if (user.isAccountLocked()) {
354 URIParam param = (URIParam) user.getField(URIParam.class);
Michael Hanl87106d12015-09-14 18:13:51 +0200355
margarethaebc54962017-05-29 13:23:07 +0200356 if (param.hasValues()) {
357 jlog.debug("Account is not yet activated for user '{}'", user.getUsername());
358 if (TimeUtils.getNow().isAfter(param.getUriExpiration())) {
359 jlog.error("URI token is expired. Deleting account for user {}", user.getUsername());
360 deleteAccount(user);
361 throw new WrappedException(
362 new KustvaktException(unknown.getId(), StatusCodes.EXPIRED,
363 "account confirmation uri has expired!", param.getUriFragment()),
364 StatusCodes.LOGIN_FAILED, username);
365 }
366 throw new WrappedException(
367 new KustvaktException(unknown.getId(), StatusCodes.ACCOUNT_NOT_CONFIRMED),
368 StatusCodes.LOGIN_FAILED, username);
369 }
370 jlog.error("ACCESS DENIED: account not active for '{}'", unknown.getUsername());
371 throw new WrappedException(new KustvaktException(unknown.getId(), StatusCodes.ACCOUNT_DEACTIVATED),
372 StatusCodes.LOGIN_FAILED, username);
373 }
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200374
margarethaebc54962017-05-29 13:23:07 +0200375 } else if (unknown instanceof ShibUser) {
376 // todo
377 }
margarethaf18298b2017-09-14 22:14:32 +0200378 jlog.debug("Authentication done: "+unknown);
margarethaebc54962017-05-29 13:23:07 +0200379 return unknown;
380 }
381
382 /**
383 * authenticate using IdM (Identitätsmanagement) accessed by LDAP.
384 *
385 * @param username
386 * @param password
387 * @param attr
388 * @return
389 * @throws KustvaktException
390 * @date 09.02.17/FB
391 */
392 // todo: what if attributes null?
Bodmo3d6bd352017-04-25 11:31:39 +0200393
margarethaebc54962017-05-29 13:23:07 +0200394 private User authenticateIdM(String username, String password, Map<String, Object> attr) throws KustvaktException {
Bodmo3d6bd352017-04-25 11:31:39 +0200395
margarethaebc54962017-05-29 13:23:07 +0200396 Map<String, Object> attributes = validator.validateMap(attr);
397 User unknown = null;
398 // just to make sure that the plain password does not appear anywhere in
399 // the logs!
Bodmo3d6bd352017-04-25 11:31:39 +0200400
margarethaebc54962017-05-29 13:23:07 +0200401 System.out.printf("Debug: authenticateIdM: entering for '%s'...\n", username);
Bodmo3d6bd352017-04-25 11:31:39 +0200402
margarethaebc54962017-05-29 13:23:07 +0200403 /**
404 * wozu Apache Validatoren für User/Passwort für IdM/LDAP? siehe
405 * validation.properties. Abgeschaltet 21.04.17/FB try {
406 * validator.validateEntry(username, Attributes.USERNAME); } catch
407 * (KustvaktException e) { throw new WrappedException(e,
408 * StatusCodes.LOGIN_FAILED, username); }
409 */
410 if (username == null || username.isEmpty() || password == null || password.isEmpty())
411 throw new WrappedException(new KustvaktException(username, StatusCodes.BAD_CREDENTIALS),
412 StatusCodes.LOGIN_FAILED);
Bodmo3d6bd352017-04-25 11:31:39 +0200413
margarethaebc54962017-05-29 13:23:07 +0200414 // LDAP Access:
415 try {
416 // todo: unknown = ...
margaretha65b67142017-05-29 16:23:16 +0200417 int ret = LdapAuth3.login(username, password, config.getLdapConfig());
margarethaebc54962017-05-29 13:23:07 +0200418 System.out.printf("Debug: autenticationIdM: Ldap.login(%s) returns: %d.\n", username, ret);
419 if (ret != LdapAuth3.LDAP_AUTH_ROK) {
420 jlog.error("LdapAuth3.login(username='{}') returns '{}'='{}'!", username, ret,
421 LdapAuth3.getErrMessage(ret));
Bodmo3d6bd352017-04-25 11:31:39 +0200422
margarethaebc54962017-05-29 13:23:07 +0200423 // mask exception to disable user guessing in possible attacks
424 /*
425 * by Hanl throw new WrappedException(new
426 * KustvaktException(username, StatusCodes.BAD_CREDENTIALS),
427 * StatusCodes.LOGIN_FAILED, username);
428 */
429 throw new WrappedException(new KustvaktException(username, StatusCodes.LDAP_BASE_ERRCODE + ret,
430 LdapAuth3.getErrMessage(ret), null), StatusCodes.LOGIN_FAILED, username);
431 }
432 } catch (LDAPException e) {
Bodmo3d6bd352017-04-25 11:31:39 +0200433
margarethaebc54962017-05-29 13:23:07 +0200434 jlog.error("Error: username='{}' -> '{}'!", username, e);
435 // mask exception to disable user guessing in possible attacks
436 /*
437 * by Hanl: throw new WrappedException(new
438 * KustvaktException(username, StatusCodes.BAD_CREDENTIALS),
439 * StatusCodes.LOGIN_FAILED, username);
440 */
441 throw new WrappedException(
442 new KustvaktException(username, StatusCodes.LDAP_BASE_ERRCODE + LdapAuth3.LDAP_AUTH_RINTERR,
443 LdapAuth3.getErrMessage(LdapAuth3.LDAP_AUTH_RINTERR), null),
444 StatusCodes.LOGIN_FAILED, username);
445 }
Bodmo3d6bd352017-04-25 11:31:39 +0200446
margarethaebc54962017-05-29 13:23:07 +0200447 // Create a User
448 // TODO: KorAPUser für solche mit einem bestehenden Account
449 // DefaultUser sonst.
450 User user = new KorAPUser();
451 user.setUsername(username);
452 /*
453 * folgender Code funktioniert hier noch nicht, da die Headers noch
454 * nicht ausgewertet worden sind - 23.05.17/FB Object o =
455 * attr.get(Attributes.LOCATION); String loc = (String)o.toString(); int
456 * location = Integer.parseInt(loc); user.setLocation(location);
457 * user.setCorpusAccess(Integer.parseInt(attr.get(Attributes.
458 * CORPUS_ACCESS).toString()));
459 */
460 unknown = user;
Michael Hanl87106d12015-09-14 18:13:51 +0200461
margarethaebc54962017-05-29 13:23:07 +0200462 jlog.trace("Authentication: found username " + unknown.getUsername());
Michael Hanl87106d12015-09-14 18:13:51 +0200463
margarethaebc54962017-05-29 13:23:07 +0200464 if (unknown instanceof KorAPUser) {
465 /*
466 * password already checked using LDAP: if (password == null ||
467 * password.isEmpty()) throw new WrappedException(new
468 * KustvaktException( unknown.getId(), StatusCodes.BAD_CREDENTIALS),
469 * StatusCodes.LOGIN_FAILED, username);
470 *
471 * KorAPUser user = (KorAPUser) unknown; boolean check =
472 * crypto.checkHash(password, user.getPassword());
473 *
474 * if (!check) { // the fail counter only applies for wrong password
475 * jlog.warn("Wrong Password!"); processLoginFail(unknown); throw
476 * new WrappedException(new KustvaktException(user.getId(),
477 * StatusCodes.BAD_CREDENTIALS), StatusCodes.LOGIN_FAILED,
478 * username); }
479 */
480 // bad credentials error has precedence over account locked or
481 // unconfirmed codes
482 // since latter can lead to account guessing of third parties
483 /*
484 * if (user.isAccountLocked()) {
485 *
486 * URIParam param = (URIParam) user.getField(URIParam.class);
487 *
488 * if (param.hasValues()) {
489 * jlog.debug("Account is not yet activated for user '{}'",
490 * user.getUsername()); if
491 * (TimeUtils.getNow().isAfter(param.getUriExpiration())) {
492 * jlog.error( "URI token is expired. Deleting account for user {}",
493 * user.getUsername()); deleteAccount(user); throw new
494 * WrappedException(new KustvaktException( unknown.getId(),
495 * StatusCodes.EXPIRED, "account confirmation uri has expired!",
496 * param.getUriFragment()), StatusCodes.LOGIN_FAILED, username); }
497 * throw new WrappedException(new KustvaktException(
498 * unknown.getId(), StatusCodes.ACCOUNT_NOT_CONFIRMED),
499 * StatusCodes.LOGIN_FAILED, username); }
500 * jlog.error("ACCESS DENIED: account not active for '{}'",
501 * unknown.getUsername()); throw new WrappedException(new
502 * KustvaktException( unknown.getId(),
503 * StatusCodes.ACCOUNT_DEACTIVATED), StatusCodes.LOGIN_FAILED,
504 * username); }
505 */
Michael Hanl87106d12015-09-14 18:13:51 +0200506
margarethaebc54962017-05-29 13:23:07 +0200507 } else if (unknown instanceof ShibUser) {
508 // todo
509 }
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200510
margarethaebc54962017-05-29 13:23:07 +0200511 jlog.debug("Authentication done: " + username);
512 return unknown;
Michael Hanl19390652016-01-16 11:01:24 +0100513
margarethaebc54962017-05-29 13:23:07 +0200514 } // authenticateIdM
Michael Hanl87106d12015-09-14 18:13:51 +0200515
margarethaebc54962017-05-29 13:23:07 +0200516 public boolean isRegistered(String username) {
517 User user;
518 if (username == null || username.isEmpty())
519 return false;
520 // throw new KustvaktException(username, StatusCodes.ILLEGAL_ARGUMENT,
521 // "username must be set", username);
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200522
margarethaebc54962017-05-29 13:23:07 +0200523 try {
524 user = entHandler.getAccount(username);
525 } catch (EmptyResultException e) {
526 jlog.debug("user does not exist ({})", username);
527 return false;
Michael Hanl87106d12015-09-14 18:13:51 +0200528
margarethaebc54962017-05-29 13:23:07 +0200529 } catch (KustvaktException e) {
530 jlog.error("KorAPException", e.string());
531 return false;
532 // throw new KustvaktException(username,
533 // StatusCodes.ILLEGAL_ARGUMENT,
534 // "username invalid", username);
535 }
536 return user != null;
537 }
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200538
margarethaebc54962017-05-29 13:23:07 +0200539 public void logout(TokenContext context) throws KustvaktException {
540 try {
541 AuthenticationIface provider = getProvider(context.getTokenType(), null);
Michael Hanl87106d12015-09-14 18:13:51 +0200542
margarethaebc54962017-05-29 13:23:07 +0200543 if (provider == null) {
544 throw new KustvaktException(StatusCodes.ILLEGAL_ARGUMENT, "provider not supported!",
545 context.getTokenType());
546 }
547 provider.removeUserSession(context.getToken());
548 } catch (KustvaktException e) {
549 throw new WrappedException(e, StatusCodes.LOGOUT_FAILED, context.toString());
550 }
551 auditing.audit(
552 AuditRecord.serviceRecord(context.getUsername(), StatusCodes.LOGOUT_SUCCESSFUL, context.toString()));
553 this.removeCacheEntry(context.getToken());
554 }
Michael Hanl87106d12015-09-14 18:13:51 +0200555
margarethaebc54962017-05-29 13:23:07 +0200556 private void processLoginFail(User user) throws KustvaktException {
557 counter.registerFail(user.getUsername());
558 if (!counter.validate(user.getUsername())) {
559 try {
560 this.lockAccount(user);
561 } catch (KustvaktException e) {
562 jlog.error("user account could not be locked", e);
563 throw new WrappedException(e, StatusCodes.UPDATE_ACCOUNT_FAILED);
564 }
565 throw new WrappedException(new KustvaktException(user.getId(), StatusCodes.ACCOUNT_DEACTIVATED),
566 StatusCodes.LOGIN_FAILED);
567 }
568 }
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200569
margarethaebc54962017-05-29 13:23:07 +0200570 public void lockAccount(User user) throws KustvaktException {
571 if (!(user instanceof KorAPUser))
572 throw new KustvaktException(StatusCodes.REQUEST_INVALID);
Michael Hanl87106d12015-09-14 18:13:51 +0200573
margarethaebc54962017-05-29 13:23:07 +0200574 KorAPUser u = (KorAPUser) user;
575 u.setAccountLocked(true);
576 jlog.info("locking account for user: {}", user.getUsername());
577 entHandler.updateAccount(u);
578 }
Michael Hanl87106d12015-09-14 18:13:51 +0200579
margarethaebc54962017-05-29 13:23:07 +0200580 public KorAPUser checkPasswordAllowance(KorAPUser user, String oldPassword, String newPassword)
581 throws KustvaktException {
582 String dbPassword = user.getPassword();
Michael Hanl87106d12015-09-14 18:13:51 +0200583
margarethaebc54962017-05-29 13:23:07 +0200584 if (oldPassword.trim().equals(newPassword.trim())) {
585 // TODO: special error StatusCodes for this?
586 throw new WrappedException(new KustvaktException(user.getId(), StatusCodes.ILLEGAL_ARGUMENT),
587 StatusCodes.PASSWORD_RESET_FAILED, newPassword);
588 }
Michael Hanl87106d12015-09-14 18:13:51 +0200589
margarethaebc54962017-05-29 13:23:07 +0200590 boolean check = crypto.checkHash(oldPassword, dbPassword);
Michael Hanl87106d12015-09-14 18:13:51 +0200591
margarethaebc54962017-05-29 13:23:07 +0200592 if (!check)
593 throw new WrappedException(new KustvaktException(user.getId(), StatusCodes.BAD_CREDENTIALS),
594 StatusCodes.PASSWORD_RESET_FAILED);
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200595
margarethaebc54962017-05-29 13:23:07 +0200596 try {
597 user.setPassword(crypto.secureHash(newPassword));
598 } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
599 throw new WrappedException(
600 new KustvaktException(user.getId(), StatusCodes.ILLEGAL_ARGUMENT, "password invalid", newPassword),
601 StatusCodes.PASSWORD_RESET_FAILED, user.toString(), newPassword);
602 }
603 return user;
604 }
Michael Hanl87106d12015-09-14 18:13:51 +0200605
margarethaebc54962017-05-29 13:23:07 +0200606 // fixme: use clientinfo for logging/auditing?! = from where did he access
607 // the reset function?
608 @Override
609 public void resetPassword(String uriFragment, String username, String newPassphrase) throws KustvaktException {
610 try {
611 validator.validateEntry(username, Attributes.USERNAME);
612 validator.validateEntry(newPassphrase, Attributes.PASSWORD);
613 } catch (KustvaktException e) {
614 jlog.error("Error: {}", e.string());
615 throw new WrappedException(
616 new KustvaktException(username, StatusCodes.ILLEGAL_ARGUMENT, "password invalid", newPassphrase),
617 StatusCodes.PASSWORD_RESET_FAILED, username, newPassphrase);
618 }
Michael Hanl87106d12015-09-14 18:13:51 +0200619
margarethaebc54962017-05-29 13:23:07 +0200620 try {
621 newPassphrase = crypto.secureHash(newPassphrase);
622 } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
623 jlog.error("Encoding/Algorithm Error", e);
624 throw new WrappedException(
625 new KustvaktException(username, StatusCodes.ILLEGAL_ARGUMENT, "password invalid", newPassphrase),
626 StatusCodes.PASSWORD_RESET_FAILED, username, uriFragment, newPassphrase);
627 }
628 int result = entHandler.resetPassphrase(username, uriFragment, newPassphrase);
Michael Hanl87106d12015-09-14 18:13:51 +0200629
margarethaebc54962017-05-29 13:23:07 +0200630 if (result == 0)
631 throw new WrappedException(
632 new KustvaktException(username, StatusCodes.EXPIRED, "URI fragment expired", uriFragment),
633 StatusCodes.PASSWORD_RESET_FAILED, username, uriFragment);
634 else if (result == 1)
635 jlog.info("successfully reset password for user {}", username);
636 }
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200637
margarethaebc54962017-05-29 13:23:07 +0200638 public void confirmRegistration(String uriFragment, String username) throws KustvaktException {
639 try {
640 validator.validateEntry(username, Attributes.USERNAME);
641 } catch (KustvaktException e) {
642 jlog.error("Error: {}", e.string());
643 throw new WrappedException(e, StatusCodes.ACCOUNT_CONFIRMATION_FAILED, username, uriFragment);
644 }
645 int r = entHandler.activateAccount(username, uriFragment);
646 if (r == 0) {
647 User user;
648 try {
649 user = entHandler.getAccount(username);
650 } catch (EmptyResultException e) {
651 throw new WrappedException(new KustvaktException(username, StatusCodes.BAD_CREDENTIALS),
652 StatusCodes.ACCOUNT_CONFIRMATION_FAILED, username, uriFragment);
653 }
654 entHandler.deleteAccount(user.getId());
655 throw new WrappedException(new KustvaktException(user.getId(), StatusCodes.EXPIRED),
656 StatusCodes.ACCOUNT_CONFIRMATION_FAILED, username, uriFragment);
657 } else if (r == 1)
658 jlog.info("successfully confirmed user registration for user {}", username);
659 // register successful audit!
660 }
Michael Hanl87106d12015-09-14 18:13:51 +0200661
margarethaebc54962017-05-29 13:23:07 +0200662 /**
663 * @param attributes
664 * @return
665 * @throws KustvaktException
666 */
667 // fixme: remove clientinfo object (not needed), use json representation to
668 // get stuff
669 public User createUserAccount(Map<String, Object> attributes, boolean confirmation_required)
670 throws KustvaktException {
671 Map<String, Object> safeMap = validator.validateMap(attributes);
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200672
margarethaebc54962017-05-29 13:23:07 +0200673 if (safeMap.get(Attributes.USERNAME) == null || ((String) safeMap.get(Attributes.USERNAME)).isEmpty())
674 throw new KustvaktException(StatusCodes.ILLEGAL_ARGUMENT, "username must be set", "username");
675 if (safeMap.get(Attributes.PASSWORD) == null || ((String) safeMap.get(Attributes.PASSWORD)).isEmpty())
676 throw new KustvaktException(safeMap.get(Attributes.USERNAME), StatusCodes.ILLEGAL_ARGUMENT,
677 "password must be set", "password");
Michael Hanlc0ed00f2016-06-23 14:33:10 +0200678
margarethaebc54962017-05-29 13:23:07 +0200679 String username = validator.validateEntry((String) safeMap.get(Attributes.USERNAME), Attributes.USERNAME);
680 String password = validator.validateEntry((String) safeMap.get(Attributes.PASSWORD), Attributes.PASSWORD);
681 String hash;
682 try {
683 hash = crypto.secureHash(password);
684 } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
685 jlog.error("Encryption error", e);
686 throw new KustvaktException(StatusCodes.ILLEGAL_ARGUMENT);
687 }
Michael Hanl87106d12015-09-14 18:13:51 +0200688
margarethaebc54962017-05-29 13:23:07 +0200689 KorAPUser user = User.UserFactory.getUser(username);
690 Object id = attributes.get(Attributes.ID);
691 if (id != null && id instanceof Integer)
692 user.setId((Integer) id);
Michael Hanl87106d12015-09-14 18:13:51 +0200693
margarethaebc54962017-05-29 13:23:07 +0200694 user.setAccountLocked(confirmation_required);
695 if (confirmation_required) {
696 URIParam param = new URIParam(crypto.createToken(),
697 TimeUtils.plusSeconds(config.getTokenTTL()).getMillis());
698 user.addField(param);
699 }
700 user.setPassword(hash);
Michael Hanl7368aa42016-02-05 18:15:47 +0100701
margarethaebc54962017-05-29 13:23:07 +0200702 String o = (String) attributes.get(Attributes.IS_ADMIN);
margaretha62055f72017-04-11 19:17:43 +0200703 boolean b = Boolean.parseBoolean(o);
704 user.setAdmin(b);
Michael Hanlc0ed00f2016-06-23 14:33:10 +0200705
margarethaebc54962017-05-29 13:23:07 +0200706 try {
707 UserDetails details = new UserDetails();
708 details.read(safeMap, true);
Michael Hanlc0ed00f2016-06-23 14:33:10 +0200709
margarethaebc54962017-05-29 13:23:07 +0200710 UserSettings settings = new UserSettings();
711 settings.read(safeMap, true);
Michael Hanl5fac8ab2016-01-29 16:33:04 +0100712
margarethaebc54962017-05-29 13:23:07 +0200713 jlog.info("Creating new user account for user {}", user.getUsername());
714 entHandler.createAccount(user);
715 if (user.isAdmin() && user instanceof KorAPUser) {
716 adminHandler.addAccount(user);
717 user.setCorpusAccess(CorpusAccess.ALL);
718 }
719 details.setUserId(user.getId());
720 settings.setUserId(user.getId());
Michael Hanl87106d12015-09-14 18:13:51 +0200721
margarethaebc54962017-05-29 13:23:07 +0200722 UserDataDbIface dao = BeansFactory.getTypeFactory().getTypeInterfaceBean(userdatadaos, UserDetails.class);
723 // todo: remove this
724 assert dao != null;
725 dao.store(details);
726 dao = BeansFactory.getTypeFactory().getTypeInterfaceBean(userdatadaos, UserSettings.class);
727 assert dao != null;
728 dao.store(settings);
729 } catch (KustvaktException e) {
730 jlog.error("Error: {}", e.string());
731 throw new WrappedException(e, StatusCodes.CREATE_ACCOUNT_FAILED, user.toString());
732 }
Michael Hanl87106d12015-09-14 18:13:51 +0200733
margarethaebc54962017-05-29 13:23:07 +0200734 auditing.audit(AuditRecord.serviceRecord(user.getUsername(), StatusCodes.CREATE_ACCOUNT_SUCCESSFUL));
735 return user;
736 }
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200737
margarethaebc54962017-05-29 13:23:07 +0200738 // todo:
739 private ShibUser createShibbUserAccount(Map<String, Object> attributes) throws KustvaktException {
740 jlog.debug("creating shibboleth user account for user attr: {}", attributes);
741 Map<String, Object> safeMap = validator.validateMap(attributes);
Michael Hanl87106d12015-09-14 18:13:51 +0200742
margarethaebc54962017-05-29 13:23:07 +0200743 // todo eppn non-unique.join with idp or use persistent_id as username
744 // identifier
745 ShibUser user = User.UserFactory.getShibInstance((String) safeMap.get(Attributes.EPPN),
746 (String) safeMap.get(Attributes.MAIL), (String) safeMap.get(Attributes.CN));
747 user.setAffiliation((String) safeMap.get(Attributes.EDU_AFFIL));
748 user.setAccountCreation(TimeUtils.getNow().getMillis());
Michael Hanlc0ed00f2016-06-23 14:33:10 +0200749
margarethaebc54962017-05-29 13:23:07 +0200750 UserDetails d = new UserDetails();
751 d.read(attributes, true);
Michael Hanlc0ed00f2016-06-23 14:33:10 +0200752
margarethaebc54962017-05-29 13:23:07 +0200753 UserSettings s = new UserSettings();
754 s.read(attributes, true);
Michael Hanlc0ed00f2016-06-23 14:33:10 +0200755
margarethaebc54962017-05-29 13:23:07 +0200756 entHandler.createAccount(user);
Michael Hanlc0ed00f2016-06-23 14:33:10 +0200757
margarethaebc54962017-05-29 13:23:07 +0200758 s.setUserId(user.getId());
759 d.setUserId(user.getId());
Michael Hanl25aac542016-02-01 18:16:44 +0100760
margarethaebc54962017-05-29 13:23:07 +0200761 UserDataDbIface dao = BeansFactory.getTypeFactory().getTypeInterfaceBean(userdatadaos, UserDetails.class);
762 assert dao != null;
763 dao.store(d);
Michael Hanl25aac542016-02-01 18:16:44 +0100764
margarethaebc54962017-05-29 13:23:07 +0200765 dao = BeansFactory.getTypeFactory().getTypeInterfaceBean(userdatadaos, UserSettings.class);
766 assert dao != null;
767 dao.store(d);
Michael Hanl25aac542016-02-01 18:16:44 +0100768
margarethaebc54962017-05-29 13:23:07 +0200769 return user;
770 }
Michael Hanl25aac542016-02-01 18:16:44 +0100771
margarethaebc54962017-05-29 13:23:07 +0200772 /**
773 * link shibboleth and korap user account to one another.
774 *
775 * @param current
776 * currently logged in user
777 * @param for_name
778 * foreign user name the current account should be linked to
779 * @param transstrat
780 * transfer status of user data (details, settings, user queries)
781 * 0 = the currently logged in data should be kept 1 = the
782 * foreign account data should be kept
783 * @throws NotAuthorizedException
784 * @throws KustvaktException
785 */
786 // todo:
787 public void accountLink(User current, String for_name, int transstrat) throws KustvaktException {
788 // User foreign = entHandler.getAccount(for_name);
Michael Hanl87106d12015-09-14 18:13:51 +0200789
margarethaebc54962017-05-29 13:23:07 +0200790 // if (current.getAccountLink() == null && current.getAccountLink()
791 // .isEmpty()) {
792 // if (current instanceof KorAPUser && foreign instanceof ShibUser) {
793 // if (transstrat == 1)
794 // current.transfer(foreign);
795 //// foreign.setAccountLink(current.getUsername());
796 //// current.setAccountLink(foreign.getUsername());
797 // // entHandler.purgeDetails(foreign);
798 // // entHandler.purgeSettings(foreign);
799 // }else if (foreign instanceof KorAPUser
800 // && current instanceof ShibUser) {
801 // if (transstrat == 0)
802 // foreign.transfer(current);
803 //// current.setAccountLink(foreign.getUsername());
804 // // entHandler.purgeDetails(current);
805 // // entHandler.purgeSettings(current);
806 // // entHandler.purgeSettings(current);
807 // }
808 // entHandler.updateAccount(current);
809 // entHandler.updateAccount(foreign);
810 // }
811 }
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200812
margarethaebc54962017-05-29 13:23:07 +0200813 // todo: test and rest usage?!
814 public boolean updateAccount(User user) throws KustvaktException {
815 boolean result;
816 if (user instanceof DemoUser)
817 throw new KustvaktException(user.getId(), StatusCodes.REQUEST_INVALID,
818 "account not updateable for demo user", user.getUsername());
819 else {
820 // crypto.validate(user);
821 try {
822 result = entHandler.updateAccount(user) > 0;
823 } catch (KustvaktException e) {
824 jlog.error("Error: {}", e.string());
825 throw new WrappedException(e, StatusCodes.UPDATE_ACCOUNT_FAILED);
826 }
827 }
828 if (result) {
829 // this.removeCacheEntry(user.getUsername());
830 auditing.audit(
831 AuditRecord.serviceRecord(user.getId(), StatusCodes.UPDATE_ACCOUNT_SUCCESSFUL, user.toString()));
832 }
833 return result;
834 }
Michael Hanl87106d12015-09-14 18:13:51 +0200835
margarethaebc54962017-05-29 13:23:07 +0200836 public boolean deleteAccount(User user) throws KustvaktException {
837 boolean result;
838 if (user instanceof DemoUser)
839 return true;
840 else {
841 try {
842 result = entHandler.deleteAccount(user.getId()) > 0;
843 } catch (KustvaktException e) {
844 jlog.error("Error: {}", e.string());
845 throw new WrappedException(e, StatusCodes.DELETE_ACCOUNT_FAILED);
846 }
847 }
848 if (result) {
849 // this.removeCacheEntry(user.getUsername());
850 auditing.audit(AuditRecord.serviceRecord(user.getUsername(), StatusCodes.DELETE_ACCOUNT_SUCCESSFUL,
851 user.toString()));
852 }
853 return result;
854 }
Michael Hanl87106d12015-09-14 18:13:51 +0200855
margarethaebc54962017-05-29 13:23:07 +0200856 public Object[] validateResetPasswordRequest(String username, String email) throws KustvaktException {
857 String uritoken;
858 validator.validateEntry(email, Attributes.EMAIL);
859 User ident;
860 try {
861 ident = entHandler.getAccount(username);
862 if (ident instanceof DemoUser)
863 // throw new
864 // NotAuthorizedException(StatusCodes.PERMISSION_DENIED,
865 // "password reset now allowed for DemoUser", "");
866 throw new WrappedException(username, StatusCodes.PASSWORD_RESET_FAILED, username);
867 } catch (EmptyResultException e) {
868 throw new WrappedException(
869 new KustvaktException(username, StatusCodes.ILLEGAL_ARGUMENT, "username not found", username),
870 StatusCodes.PASSWORD_RESET_FAILED, username);
871 }
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200872
margarethaebc54962017-05-29 13:23:07 +0200873 Userdata data = this.getUserData(ident, UserDetails.class);
874 KorAPUser user = (KorAPUser) ident;
Michael Hanl87106d12015-09-14 18:13:51 +0200875
margarethaebc54962017-05-29 13:23:07 +0200876 if (!email.equals(data.get(Attributes.EMAIL)))
877 // throw new NotAuthorizedException(StatusCodes.ILLEGAL_ARGUMENT,
878 // "invalid parameter: email", "email");
879 throw new WrappedException(
880 new KustvaktException(user.getId(), StatusCodes.ILLEGAL_ARGUMENT, "email invalid", email),
881 StatusCodes.PASSWORD_RESET_FAILED, email);
882 uritoken = crypto.encodeBase();
883 URIParam param = new URIParam(uritoken, TimeUtils.plusHours(24).getMillis());
884 user.addField(param);
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200885
margarethaebc54962017-05-29 13:23:07 +0200886 try {
887 entHandler.updateAccount(user);
888 } catch (KustvaktException e) {
889 jlog.error("Error ", e.string());
890 throw new WrappedException(e, StatusCodes.PASSWORD_RESET_FAILED);
891 }
892 return new Object[] { uritoken, TimeUtils.format(param.getUriExpiration()) };
893 }
Michael Hanl87106d12015-09-14 18:13:51 +0200894
margaretha38d530e2017-07-11 19:06:50 +0200895 // EM: not in the new DB
margarethaebc54962017-05-29 13:23:07 +0200896 @Override
897 public <T extends Userdata> T getUserData(User user, Class<T> clazz) throws WrappedException {
margarethaebc54962017-05-29 13:23:07 +0200898 try {
899 UserDataDbIface<T> dao = BeansFactory.getTypeFactory()
900 .getTypeInterfaceBean(BeansFactory.getKustvaktContext().getUserDataProviders(), clazz);
901 T data = null;
902 if (dao != null)
903 data = dao.get(user);
Michael Hanl87106d12015-09-14 18:13:51 +0200904
margarethaebc54962017-05-29 13:23:07 +0200905 if (data == null)
margarethaf6d5a822017-10-19 19:51:20 +0200906 throw new KustvaktException(user.getId(), StatusCodes.NO_RESULT_FOUND, "No data found!",
margarethaebc54962017-05-29 13:23:07 +0200907 clazz.getSimpleName());
908 return data;
909 } catch (KustvaktException e) {
910 jlog.error("Error during user data retrieval: {}", e.getEntity());
911 throw new WrappedException(e, StatusCodes.GET_ACCOUNT_FAILED);
912 }
913 }
Michael Hanl5fac8ab2016-01-29 16:33:04 +0100914
margarethaebc54962017-05-29 13:23:07 +0200915 // todo: cache userdata outside of the user object!
916 @Override
917 public void updateUserData(Userdata data) throws WrappedException {
918 try {
919 data.validate(this.validator);
920 UserDataDbIface dao = BeansFactory.getTypeFactory()
921 .getTypeInterfaceBean(BeansFactory.getKustvaktContext().getUserDataProviders(), data.getClass());
922 if (dao != null)
923 dao.update(data);
924 } catch (KustvaktException e) {
925 jlog.error("Error during update of user data!", e.getEntity());
926 throw new WrappedException(e, StatusCodes.UPDATE_ACCOUNT_FAILED);
927 }
928 }
Michael Hanl87106d12015-09-14 18:13:51 +0200929}