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