001/* 002 * Copyright 2017 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.core.authentication.token; 017 018import java.io.IOException; 019import java.io.InputStream; 020import java.io.UnsupportedEncodingException; 021import java.sql.Connection; 022import java.sql.PreparedStatement; 023import java.sql.ResultSet; 024import java.sql.SQLException; 025import java.sql.Timestamp; 026import java.sql.Types; 027import java.util.ArrayList; 028import java.util.Base64; 029import java.util.Collections; 030import java.util.Date; 031import java.util.List; 032import java.util.Map; 033import java.util.Set; 034import java.util.stream.Collectors; 035 036import org.apache.avalon.framework.activity.Initializable; 037import org.apache.avalon.framework.component.Component; 038import org.apache.avalon.framework.service.ServiceException; 039import org.apache.avalon.framework.service.ServiceManager; 040import org.apache.avalon.framework.service.Serviceable; 041import org.apache.commons.codec.digest.DigestUtils; 042import org.apache.commons.io.IOUtils; 043import org.apache.commons.lang3.RandomStringUtils; 044import org.apache.commons.lang3.StringUtils; 045 046import org.ametys.core.datasource.ConnectionHelper; 047import org.ametys.core.datasource.dbtype.SQLDatabaseTypeExtensionPoint; 048import org.ametys.core.ui.Callable; 049import org.ametys.core.user.CurrentUserProvider; 050import org.ametys.core.user.UserIdentity; 051import org.ametys.core.user.UserManager; 052import org.ametys.core.util.JSONUtils; 053import org.ametys.runtime.config.Config; 054import org.ametys.runtime.plugin.component.AbstractLogEnabled; 055 056/** 057 * The component to handle temporary authentication token.<br> 058 * Token can only be used once and are available for a short time only. 059 */ 060public class AuthenticationTokenManager extends AbstractLogEnabled implements Component, Serviceable, Initializable 061{ 062 /** The avalon role */ 063 public static final String ROLE = AuthenticationTokenManager.class.getName(); 064 065 /** The separator in token */ 066 public static final String TOKEN_SEPARATOR = "#"; 067 068 /** The user token type */ 069 public static final String USER_TOKEN_TYPE = "User"; 070 071 /** all fields without login and population_id */ 072 private static final String TOKEN_SQL_GET_FIELDS = "id, token, salt, creation_date, end_date, last_update_date, nb_uses_left, auto_renew_duration, context, type, token_comment"; 073 074 /** all fields without id and last_update_date */ 075 private static final String TOKEN_SQL_SET_FIELDS = "login, population_id, token, salt, creation_date, end_date, nb_uses_left, auto_renew_duration, context, type, token_comment"; 076 077 private ServiceManager _manager; 078 079 private CurrentUserProvider _currentUserProvider; 080 081 private String _datasourceId; 082 083 private SQLDatabaseTypeExtensionPoint _sqlDatabaseTypeExtensionPoint; 084 085 private JSONUtils _jsonUtils; 086 087 private UserManager _userManager; 088 089 public void service(ServiceManager manager) throws ServiceException 090 { 091 _manager = manager; 092 _sqlDatabaseTypeExtensionPoint = (SQLDatabaseTypeExtensionPoint) manager.lookup(SQLDatabaseTypeExtensionPoint.ROLE); 093 _jsonUtils = (JSONUtils) manager.lookup(JSONUtils.ROLE); 094 _userManager = (UserManager) manager.lookup(UserManager.ROLE); 095 } 096 097 public void initialize() throws Exception 098 { 099 _datasourceId = Config.getInstance() != null ? Config.getInstance().getValue("runtime.assignments.authenticationtokens") : ""; 100 } 101 102 private CurrentUserProvider _getCurrentUserProvider() throws RuntimeException 103 { 104 if (_currentUserProvider == null) 105 { 106 try 107 { 108 _currentUserProvider = (CurrentUserProvider) _manager.lookup(CurrentUserProvider.ROLE); 109 } 110 catch (ServiceException e) 111 { 112 throw new RuntimeException(e); 113 } 114 } 115 return _currentUserProvider; 116 } 117 118 /** 119 * Get the existing tokens for the connected user 120 * 121 * @param type The type of tokens to return. null to return all. 122 * @return The tokens 123 * @throws RuntimeException If there is no user connected or if there is a 124 * database error 125 */ 126 public List<Token> getTokens(String type) throws RuntimeException 127 { 128 return getTokens(_getCurrentUserProvider().getUser(), type); 129 } 130 131 /** 132 * Get the existing tokens for this user 133 * 134 * @param type The type of tokens to return. null to return all. 135 * @param user The user. Cannot be null 136 * @return The tokens identifier and associated comment 137 * @throws RuntimeException If the user is null or if there is a database 138 * error 139 */ 140 public List<Token> getTokens(UserIdentity user, String type) throws RuntimeException 141 { 142 if (user == null) 143 { 144 throw new RuntimeException("Cannot generate a temporary authentication token for a null user"); 145 } 146 147 List<Token> tokens = new ArrayList<>(); 148 149 Connection connection = null; 150 try 151 { 152 connection = ConnectionHelper.getConnection(_datasourceId); 153 154 // Delete old entries 155 _deleteOldTokens(connection); 156 157 try (PreparedStatement selectStatement = _getSelectUserTokenStatement(connection, user.getLogin(), user.getPopulationId(), type); 158 ResultSet resultSet = selectStatement.executeQuery()) 159 { 160 // Find the database entry using this token 161 while (resultSet.next()) 162 { 163 Token token = _getTokenFromResultSet(resultSet, connection); 164 tokens.add(token); 165 } 166 } 167 } 168 catch (Exception e) 169 { 170 getLogger().error("Communication error with the database", e); 171 } 172 finally 173 { 174 ConnectionHelper.cleanup(connection); 175 } 176 177 return tokens; 178 } 179 180 /** 181 * Generates a new token for the current user 182 * 183 * @param duration The time the token is valid in seconds. 0 means for ever 184 * and moreover the ticket will be reusable. 185 * @param type The type of token. Mandatory but can be anything you want 186 * between 1 to 32 characters. Such as "Cookie". 187 * @param comment An optional token comment to remember the reason of its 188 * creation 189 * @return The token 190 * @throws RuntimeException If the user is not authenticated, or if there is 191 * a database error 192 */ 193 public String generateToken(long duration, String type, String comment) throws RuntimeException 194 { 195 return generateToken(_getCurrentUserProvider().getUser(), duration, type, comment); 196 } 197 198 /** 199 * Generates a new token 200 * 201 * @param user The user that will be authenticated with the token 202 * @param duration The time the token is valid in seconds. 0 means for ever 203 * and moreover the ticket will be reusable 204 * @param type The type of token. Mandatory but can be anything you want 205 * between 1 to 32 characters. Such as "Cookie". 206 * @param comment An optional token comment to remember the reason of its 207 * creation 208 * @return The token 209 * @throws RuntimeException If the user is null or if there is a database 210 * error or if duration is negative 211 */ 212 public String generateToken(UserIdentity user, long duration, String type, String comment) throws RuntimeException 213 { 214 return generateToken(user, duration, false, null, null, type, comment); 215 } 216 /** 217 * Generates a new token 218 * 219 * @param user The user that will be authenticated with the token 220 * @param duration The time the token is valid in seconds. 0 means for ever 221 * and moreover the ticket will be reusable 222 * @param nbUsesLeft number of available uses (null for no limit) 223 * @param type The type of token. Mandatory but can be anything you want 224 * between 1 to 32 characters. Such as "Cookie". 225 * @param comment An optional token comment to remember the reason of its 226 * creation 227 * @return The token 228 * @throws RuntimeException If the user is null or if there is a database 229 * error or if duration is negative 230 */ 231 public String generateToken(UserIdentity user, long duration, Integer nbUsesLeft, String type, String comment) throws RuntimeException 232 { 233 return generateToken(user, duration, false, nbUsesLeft, null, type, comment); 234 } 235 236 /** 237 * Generates a new token 238 * 239 * @param user The user that will be authenticated with the token 240 * @param duration The time the token is valid in seconds. 0 means for ever 241 * and moreover the ticket will be reusable 242 * @param autoRenewDuration true to automatically renew token if used before it's expiration 243 * @param nbUsesLeft number of available uses (null for no limit) 244 * @param contexts contexts where the token can be used 245 * @param type The type of token. Mandatory but can be anything you want 246 * between 1 to 32 characters. Such as "Cookie". 247 * @param comment An optional token comment to remember the reason of its 248 * creation 249 * @return The token 250 * @throws RuntimeException If the user is null or if there is a database 251 * error or if duration is negative 252 */ 253 public String generateToken(UserIdentity user, long duration, boolean autoRenewDuration, Integer nbUsesLeft, Set<String> contexts, String type, String comment) throws RuntimeException 254 { 255 if (user == null) 256 { 257 throw new RuntimeException("Cannot generate a temporary authentication token for a null user"); 258 } 259 else if (duration < 0) 260 { 261 throw new RuntimeException("Cannot generate a token for a negative duration [" + duration + "]"); 262 } 263 264 String token = RandomStringUtils.randomAlphanumeric(duration == 0 ? 64 : 16); 265 String salt = RandomStringUtils.randomAlphanumeric(48); 266 Timestamp creationDateTime = new Timestamp(new Date().getTime()); 267 Timestamp endTime = duration > 0 ? new Timestamp(System.currentTimeMillis() + duration * 1000) : null; 268 String hashedTokenAndSalt = DigestUtils.sha512Hex(token + salt); 269 270 271 _generateToken(user, duration, autoRenewDuration, nbUsesLeft, contexts, type, comment, hashedTokenAndSalt, salt, creationDateTime, endTime); 272 273 String fullToken = user.getPopulationId() + TOKEN_SEPARATOR + user.getLogin() + TOKEN_SEPARATOR + token; 274 275 try 276 { 277 return Base64.getEncoder().withoutPadding().encodeToString(fullToken.getBytes("UTF-8")); 278 } 279 catch (UnsupportedEncodingException e) 280 { 281 // can't occur ... 282 throw new RuntimeException(e); 283 } 284 } 285 286 private void _generateToken(UserIdentity user, long duration, boolean autoRenewDuration, Integer nbUsesLeft, Set<String> contexts, String type, String comment, String hashedTokenAndSalt, String salt, Timestamp creationDateTime, Timestamp endTime) throws RuntimeException 287 { 288 ResultSet rs = null; 289 Connection connection = null; 290 PreparedStatement statement = null; 291 try 292 { 293 connection = ConnectionHelper.getConnection(_datasourceId); 294 String dbType = ConnectionHelper.getDatabaseType(connection); 295 if (ConnectionHelper.DATABASE_ORACLE.equals(dbType)) 296 { 297 statement = connection.prepareStatement("SELECT seq_authenticationtoken.nextval FROM dual"); 298 rs = statement.executeQuery(); 299 300 String id = null; 301 if (rs.next()) 302 { 303 id = rs.getString(1); 304 } 305 ConnectionHelper.cleanup(rs); 306 ConnectionHelper.cleanup(statement); 307 statement = connection.prepareStatement( 308 "INSERT INTO Authentication_Token (id, " + TOKEN_SQL_SET_FIELDS + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); 309 int nextParam = 1; 310 statement.setString(nextParam++, id); 311 statement.setString(nextParam++, user.getLogin()); 312 statement.setString(nextParam++, user.getPopulationId()); 313 statement.setString(nextParam++, hashedTokenAndSalt); 314 statement.setString(nextParam++, salt); 315 statement.setTimestamp(nextParam++, creationDateTime); 316 statement.setTimestamp(nextParam++, endTime); 317 if (nbUsesLeft == null) 318 { 319 statement.setNull(nextParam++, java.sql.Types.INTEGER); 320 } 321 else 322 { 323 statement.setInt(nextParam++, nbUsesLeft); 324 } 325 326 if (!autoRenewDuration) 327 { 328 statement.setNull(nextParam++, java.sql.Types.BIGINT); 329 } 330 else 331 { 332 statement.setLong(nextParam++, duration); 333 } 334 335 if (contexts == null) 336 { 337 statement.setNull(nextParam++, java.sql.Types.VARCHAR); 338 } 339 else 340 { 341 String contextString = _contextsToString(contexts); 342 statement.setString(nextParam++, contextString); 343 } 344 statement.setString(nextParam++, type); 345 if (comment == null) 346 { 347 statement.setNull(nextParam++, Types.BLOB); 348 } 349 else 350 { 351 _sqlDatabaseTypeExtensionPoint.setBlob(dbType, statement, nextParam++, comment); 352 } 353 } 354 else 355 { 356 statement = connection.prepareStatement( 357 "INSERT INTO Authentication_Token (" + TOKEN_SQL_SET_FIELDS + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); 358 int nextParam = 1; 359 statement.setString(nextParam++, user.getLogin()); 360 statement.setString(nextParam++, user.getPopulationId()); 361 statement.setString(nextParam++, hashedTokenAndSalt); 362 statement.setString(nextParam++, salt); 363 statement.setTimestamp(nextParam++, creationDateTime); 364 statement.setTimestamp(nextParam++, endTime); 365 366 if (nbUsesLeft == null) 367 { 368 statement.setNull(nextParam++, java.sql.Types.INTEGER); 369 } 370 else 371 { 372 statement.setInt(nextParam++, nbUsesLeft); 373 } 374 375 if (!autoRenewDuration) 376 { 377 statement.setNull(nextParam++, java.sql.Types.BIGINT); 378 } 379 else 380 { 381 statement.setLong(nextParam++, duration); 382 } 383 384 if (contexts == null) 385 { 386 statement.setNull(nextParam++, java.sql.Types.VARCHAR); 387 } 388 else 389 { 390 String contextString = _contextsToString(contexts); 391 statement.setString(nextParam++, contextString); 392 } 393 394 statement.setString(nextParam++, type); 395 _sqlDatabaseTypeExtensionPoint.setBlob(dbType, statement, nextParam++, comment); 396 } 397 398 statement.executeUpdate(); 399 } 400 catch (SQLException | UnsupportedEncodingException e) 401 { 402 throw new RuntimeException(e); 403 } 404 finally 405 { 406 ConnectionHelper.cleanup(rs); 407 ConnectionHelper.cleanup(connection); 408 } 409 } 410 411 private String _contextsToString(Set<String> contexts) 412 { 413 return _jsonUtils.convertObjectToJson(contexts); 414 } 415 416 private Set<String> _convertStringToContexts(String contexts) 417 { 418 if (contexts == null) 419 { 420 return Collections.EMPTY_SET; 421 } 422 try 423 { 424 List<Object> jsonList = _jsonUtils.convertJsonToList(contexts); 425 Set<String> result = jsonList.stream() 426 .filter(String.class::isInstance) 427 .map(String.class::cast) 428 .collect(Collectors.toSet()); 429 430 return result; 431 } 432 catch (IllegalArgumentException e) 433 { 434 // The input is not a json array, so it is just a string 435 return Collections.singleton(contexts); 436 } 437 } 438 439 private UserIdentity _validateToken(String encodedToken, String context, boolean forceRemove) 440 { 441 String token; 442 try 443 { 444 token = new String(Base64.getDecoder().decode(encodedToken), "UTF-8"); 445 } 446 catch (UnsupportedEncodingException e) 447 { 448 // can't occur ... 449 throw new RuntimeException(e); 450 } 451 catch (Exception e) 452 { 453 // Exception occured during token decoding 454 return null; 455 } 456 457 String[] split = StringUtils.split(token, TOKEN_SEPARATOR); 458 if (split == null || split.length != 3) 459 { 460 return null; 461 } 462 463 String populationId = split[0]; 464 String login = split[1]; 465 String tokenPart = split[2]; 466 467 Connection connection = null; 468 try 469 { 470 connection = ConnectionHelper.getConnection(_datasourceId); 471 472 // Delete old entries 473 _deleteOldTokens(connection); 474 475 try ( 476 PreparedStatement selectStatement = _getSelectUserTokenStatement(connection, login, populationId, null); 477 ResultSet resultSet = selectStatement.executeQuery() 478 ) 479 { 480 // Find the database entry using this token 481 while (resultSet.next()) 482 { 483 if (resultSet.getString("token").equals(DigestUtils.sha512Hex(tokenPart + resultSet.getString("salt")))) 484 { 485 Token tokenToUpdate = _getTokenFromResultSet(resultSet, connection); 486 // If the token doesn't have a context, this one is always valid 487 // Else, the token context must be equal to the token context the context method parameter 488 if (tokenToUpdate.getContexts() != null && tokenToUpdate.getContexts().size() > 0 && !tokenToUpdate.getContexts().contains(context)) 489 { 490 continue; 491 } 492 493 // Delete it 494 if (forceRemove) 495 { 496 _deleteUserToken(connection, tokenToUpdate.getId()); 497 } 498 else 499 { 500 _updateUserToken(connection, tokenToUpdate); 501 } 502 503 // Control that the user exists 504 UserIdentity identity = new UserIdentity(login, populationId); 505 if (_userManager.getUser(identity) != null) 506 { 507 return identity; 508 } 509 } 510 } 511 } 512 } 513 catch (Exception e) 514 { 515 getLogger().error("Communication error with the database", e); 516 } 517 finally 518 { 519 ConnectionHelper.cleanup(connection); 520 } 521 522 return null; 523 } 524 525 /** 526 * Check if a token is valid and return the user 527 * 528 * @param token The token to validate 529 * @return The user associated to the valid token, null otherwise 530 */ 531 public UserIdentity validateToken(String token) 532 { 533 return validateToken(token, null); 534 } 535 536 /** 537 * Check if a token is valid and return the user 538 * @param token The token to validate 539 * @param context context to validate the token with 540 * @return The user associated to the valid token, null otherwise 541 */ 542 public UserIdentity validateToken(String token, String context) 543 { 544 return _validateToken(token, context, false); 545 } 546 547 /** 548 * Destroy the given token 549 * 550 * @param token The token to remove 551 * @param context context of the token (null for no context) 552 */ 553 public void deleteTokenByValue(String token, String context) 554 { 555 _validateToken(token, context, true); 556 } 557 558 /** 559 * Destroy the given token 560 * 561 * @param tokenId The token identifier to remove 562 */ 563 public void deleteTokenById(Integer tokenId) 564 { 565 Connection connection = null; 566 try 567 { 568 connection = ConnectionHelper.getConnection(_datasourceId); 569 570 _deleteUserToken(connection, tokenId); 571 } 572 catch (SQLException e) 573 { 574 throw new RuntimeException("Could not delete the authentication token with identifier " + tokenId, e); 575 } 576 finally 577 { 578 ConnectionHelper.cleanup(connection); 579 } 580 } 581 582 /** 583 * Generates the sql statement that deletes the entries of the users token 584 * database that are old 585 * 586 * @param connection the database's session 587 * @throws SQLException if a sql exception occurs 588 */ 589 private void _deleteOldTokens(Connection connection) throws SQLException 590 { 591 try (PreparedStatement statement = connection.prepareStatement("DELETE FROM Authentication_Token WHERE end_date < ? OR nb_uses_left = ?")) 592 { 593 statement.setTimestamp(1, new Timestamp(System.currentTimeMillis())); 594 statement.setInt(2, 0); 595 statement.executeUpdate(); 596 } 597 } 598 599 /** 600 * Generates the statement that selects the users having the specified login 601 * in the Authentication_Token table 602 * 603 * @param connection the database's session 604 * @param login The login of the user 605 * @param populationId The populationId of the user 606 * @param type The type to filter or null to get all 607 * @return the retrieve statement 608 * @throws SQLException if a sql exception occurs 609 */ 610 private PreparedStatement _getSelectUserTokenStatement(Connection connection, String login, String populationId, String type) throws SQLException 611 { 612 String sqlRequest = "SELECT " + TOKEN_SQL_GET_FIELDS + " FROM Authentication_Token WHERE login=? AND population_id=?" 613 + (type != null ? " AND type=?" : ""); 614 615 PreparedStatement statement = connection.prepareStatement(sqlRequest); 616 int nextParam = 1; 617 statement.setString(nextParam++, login); 618 statement.setString(nextParam++, populationId); 619 if (type != null) 620 { 621 statement.setString(nextParam++, type); 622 } 623 624 return statement; 625 } 626 private Token _getTokenFromResultSet(ResultSet resultSet, Connection connection) throws SQLException, IOException 627 { 628 String dbType = ConnectionHelper.getDatabaseType(connection); 629 String comment = null; 630 try (InputStream blob = _sqlDatabaseTypeExtensionPoint.getBlob(dbType, resultSet, "token_comment")) 631 { 632 if (blob != null) 633 { 634 comment = IOUtils.toString(blob, "UTF-8"); 635 } 636 } 637 638 Integer nbUsesLeft = resultSet.getInt("nb_uses_left"); 639 if (resultSet.wasNull()) 640 { 641 nbUsesLeft = null; 642 } 643 644 Long autoRenewDuration = resultSet.getLong("auto_renew_duration"); 645 if (resultSet.wasNull()) 646 { 647 autoRenewDuration = null; 648 } 649 String contextString = resultSet.getString("context"); 650 Set<String> contexts = _convertStringToContexts(contextString); 651 Token token = new Token(resultSet.getInt("id"), resultSet.getString("type"), comment, resultSet.getTimestamp("creation_date"), 652 resultSet.getTimestamp("end_date"), resultSet.getTimestamp("last_update_date"), nbUsesLeft, autoRenewDuration, contexts); 653 return token; 654 } 655 656 /** 657 * Deletes the database entry that has this token 658 * 659 * @param connection the database's session 660 * @param id the token id 661 * @throws SQLException if an error occurred 662 */ 663 private void _deleteUserToken(Connection connection, Integer id) throws SQLException 664 { 665 try (PreparedStatement statement = connection.prepareStatement("DELETE FROM Authentication_Token WHERE id = ?")) 666 { 667 statement.setInt(1, id); 668 statement.executeUpdate(); 669 } 670 } 671 672 /** 673 * Update the last update date in the database 674 * 675 * @param connection the database's session 676 * @param token the token 677 * @throws SQLException if an error occurred 678 */ 679 private void _updateUserToken(Connection connection, Token token) throws SQLException 680 { 681 Integer nbUsesLeft = token.getNbUsesLeft(); 682 if (nbUsesLeft != null && nbUsesLeft > 0) 683 { 684 nbUsesLeft--; 685 } 686 687 // Delete if no uses left 688 if (nbUsesLeft != null && nbUsesLeft == 0) 689 { 690 _deleteUserToken(connection, token.getId()); 691 } 692 // Update last update_date and nb_use_left if needed 693 // And update end_date if the token have auto renew 694 else if (token.getAutoRenewDuration() != null) 695 { 696 Long autoRenewDuration = token.getAutoRenewDuration(); 697 Timestamp endDate = new Timestamp(new Date().getTime() + autoRenewDuration * 1000); 698 699 try (PreparedStatement statement = connection.prepareStatement("UPDATE Authentication_Token SET last_update_date = ?, end_date = ?, nb_uses_left = ? WHERE id = ?")) 700 { 701 Timestamp lastUpdateDate = new Timestamp(new Date().getTime()); 702 statement.setTimestamp(1, lastUpdateDate); 703 statement.setTimestamp(2, endDate); 704 if (nbUsesLeft == null) 705 { 706 statement.setNull(3, java.sql.Types.INTEGER); 707 } 708 else 709 { 710 statement.setInt(3, nbUsesLeft); 711 } 712 statement.setInt(4, token.getId()); 713 statement.executeUpdate(); 714 } 715 } 716 else 717 { 718 try (PreparedStatement statement = connection.prepareStatement("UPDATE Authentication_Token SET last_update_date = ?, nb_uses_left = ? WHERE id = ?")) 719 { 720 Timestamp lastUpdateDate = new Timestamp(new Date().getTime()); 721 statement.setTimestamp(1, lastUpdateDate); 722 if (nbUsesLeft == null) 723 { 724 statement.setNull(2, java.sql.Types.INTEGER); 725 } 726 else 727 { 728 statement.setInt(2, nbUsesLeft); 729 } 730 statement.setInt(3, token.getId()); 731 statement.executeUpdate(); 732 } 733 } 734 } 735 736 /** 737 * Generate a new authentication token 738 * 739 * @param parameters a map of the following parameters for the 740 * authentication token : description 741 * @return The generated token 742 */ 743 @Callable 744 public String generateAuthenticationToken(Map<String, Object> parameters) 745 { 746 String description = (String) parameters.get("description"); 747 String generateToken = generateToken(0, USER_TOKEN_TYPE, description); 748 749 return generateToken; 750 } 751 752 /** 753 * Delete one or multiples authentication token 754 * 755 * @param ids a list of authentication token ids 756 */ 757 @Callable 758 public void deleteAuthenticationToken(List<Integer> ids) 759 { 760 for (Integer tokenId : ids) 761 { 762 deleteTokenById(tokenId); 763 } 764 } 765 766 /** 767 * An Ametys authentication token 768 */ 769 public static class Token 770 { 771 /** The token identifier */ 772 protected Integer _id; 773 774 /** The token type */ 775 protected String _type; 776 777 /** The token associated comment */ 778 protected String _comment; 779 780 /** The token creation date */ 781 protected Date _creationDate; 782 783 /** The token end date */ 784 protected Date _endDate; 785 786 /** The token last update date */ 787 protected Date _lastUpdateDate; 788 789 /** The token number of use left */ 790 protected Integer _nbUsesLeft; 791 792 /** The token auto renewal duration, in seconds */ 793 protected Long _autoRenewDuration; 794 795 /** The token context */ 796 protected Set<String> _contexts; 797 798 /** 799 * Creates a Token 800 * 801 * @param id The identifier 802 * @param type The type of token 803 * @param comment The comment. Can be null. 804 * @param creationDate The creation date. Can be null. 805 * @param endDate The end date. Can be null. 806 * @param lastUpdateDate The last update date. Can be null. 807 * @param nbUsesLeft nb of uses left for this token (null for no limitation) 808 * @param autoRenewDuration duration that will be added (from "now") each time the token is updated 809 * @param contexts contexts of the token (ressource id for example) 810 */ 811 protected Token(Integer id, String type, String comment, Date creationDate, Date endDate, Date lastUpdateDate, Integer nbUsesLeft, Long autoRenewDuration, Set<String> contexts) 812 { 813 _id = id; 814 _type = type; 815 _comment = comment; 816 _creationDate = creationDate; 817 _endDate = endDate; 818 _lastUpdateDate = lastUpdateDate; 819 _nbUsesLeft = nbUsesLeft; 820 _autoRenewDuration = autoRenewDuration; 821 _contexts = contexts; 822 } 823 824 /** 825 * Get the token identifier 826 * 827 * @return The identifier 828 */ 829 public Integer getId() 830 { 831 return _id; 832 } 833 834 /** 835 * Get the token type 836 * 837 * @return The type 838 */ 839 public String getType() 840 { 841 return _type; 842 } 843 844 /** 845 * Get the associated creation comment 846 * 847 * @return The comment or null 848 */ 849 public String getComment() 850 { 851 return _comment; 852 } 853 854 /** 855 * Get the creation date of the token 856 * 857 * @return The creation date or null 858 */ 859 public Date getCreationDate() 860 { 861 return _creationDate; 862 } 863 864 /** 865 * Get the end date of the token validity 866 * 867 * @return The end date or null 868 */ 869 public Date getEndDate() 870 { 871 return _endDate; 872 } 873 874 /** 875 * Get the last update date of the token 876 * 877 * @return The last update date or null 878 */ 879 public Date getLastUpdateDate() 880 { 881 return _endDate; 882 } 883 884 /** 885 * Get the duration which the token should be automatically renewed on each use, in seconds 886 * 887 * @return The auto renewal duration in seconds or null if not applicable 888 */ 889 public Long getAutoRenewDuration() 890 { 891 return _autoRenewDuration; 892 } 893 894 /** 895 * Get the context on which the token can be used 896 * 897 * @return The token contexts or null if not applicable 898 */ 899 public Set<String> getContexts() 900 { 901 return _contexts; 902 } 903 904 /** 905 * Get the number of uses allowed for this token 906 * 907 * @return The number of allowed uses or null if not applicable 908 */ 909 public Integer getNbUsesLeft() 910 { 911 return _nbUsesLeft; 912 } 913 914 915 } 916}