001/******************************************************************************* 002 * Copyright 2017 The MIT Internet Trust Consortium 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 *******************************************************************************/ 016 017package org.mitre.uma.service.impl; 018 019import static org.mitre.util.JsonUtils.readSet; 020 021import java.io.IOException; 022import java.util.HashMap; 023import java.util.HashSet; 024import java.util.Map; 025import java.util.Set; 026 027import org.mitre.oauth2.model.OAuth2AccessTokenEntity; 028import org.mitre.oauth2.model.RegisteredClient; 029import org.mitre.oauth2.repository.OAuth2TokenRepository; 030import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor; 031import org.mitre.openid.connect.service.MITREidDataService; 032import org.mitre.openid.connect.service.MITREidDataServiceExtension; 033import org.mitre.openid.connect.service.MITREidDataServiceMaps; 034import org.mitre.openid.connect.service.impl.MITREidDataServiceSupport; 035import org.mitre.uma.model.Claim; 036import org.mitre.uma.model.Permission; 037import org.mitre.uma.model.PermissionTicket; 038import org.mitre.uma.model.Policy; 039import org.mitre.uma.model.ResourceSet; 040import org.mitre.uma.model.SavedRegisteredClient; 041import org.mitre.uma.repository.PermissionRepository; 042import org.mitre.uma.repository.ResourceSetRepository; 043import org.mitre.uma.service.SavedRegisteredClientService; 044import org.slf4j.Logger; 045import org.slf4j.LoggerFactory; 046import org.springframework.beans.factory.annotation.Autowired; 047import org.springframework.stereotype.Service; 048 049import com.google.gson.JsonElement; 050import com.google.gson.JsonParser; 051import com.google.gson.stream.JsonReader; 052import com.google.gson.stream.JsonToken; 053import com.google.gson.stream.JsonWriter; 054 055/** 056 * @author jricher 057 * 058 */ 059@Service("umaDataExtension_1_3") 060public class UmaDataServiceExtension_1_3 extends MITREidDataServiceSupport implements MITREidDataServiceExtension { 061 062 private static final String THIS_VERSION = MITREidDataService.MITREID_CONNECT_1_3; 063 064 private static final String REGISTERED_CLIENT = "registeredClient"; 065 private static final String URI = "uri"; 066 private static final String NAME = "name"; 067 private static final String TYPE = "type"; 068 private static final String VALUE = "value"; 069 private static final String CLIENT_ID = "clientId"; 070 private static final String EXPIRATION = "expiration"; 071 private static final String ID = "id"; 072 private static final String ICON_URI = "iconUri"; 073 private static final String OWNER = "owner"; 074 private static final String POLICIES = "policies"; 075 private static final String SCOPES = "scopes"; 076 private static final String CLAIMS_REQUIRED = "claimsRequired"; 077 private static final String ISSUER = "issuer"; 078 private static final String CLAIM_TOKEN_FORMAT = "claimTokenFormat"; 079 private static final String CLAIM_TYPE = "claimType"; 080 private static final String FRIENDLY_NAME = "friendlyName"; 081 private static final String PERMISSIONS = "permissions"; 082 private static final String RESOURCE_SET = "resourceSet"; 083 private static final String PERMISSION_TICKETS = "permissionTickets"; 084 private static final String PERMISSION = "permission"; 085 private static final String TICKET = "ticket"; 086 private static final String CLAIMS_SUPPLIED = "claimsSupplied"; 087 private static final String SAVED_REGISTERED_CLIENTS = "savedRegisteredClients"; 088 private static final String RESOURCE_SETS = "resourceSets"; 089 private static final String TOKEN_PERMISSIONS = "tokenPermissions"; 090 private static final String TOKEN_ID = "tokenId"; 091 092 private static final Logger logger = LoggerFactory.getLogger(UmaDataServiceExtension_1_3.class); 093 094 095 096 @Autowired 097 private SavedRegisteredClientService registeredClientService; 098 @Autowired 099 private ResourceSetRepository resourceSetRepository; 100 @Autowired 101 private PermissionRepository permissionRepository; 102 @Autowired 103 private OAuth2TokenRepository tokenRepository; 104 105 private Map<Long, Set<Long>> tokenToPermissionRefs = new HashMap<>(); 106 107 /* (non-Javadoc) 108 * @see org.mitre.openid.connect.service.MITREidDataServiceExtension#supportsVersion(java.lang.String) 109 */ 110 @Override 111 public boolean supportsVersion(String version) { 112 return THIS_VERSION.equals(version); 113 114 } 115 116 /* (non-Javadoc) 117 * @see org.mitre.openid.connect.service.MITREidDataServiceExtension#exportExtensionData(com.google.gson.stream.JsonWriter) 118 */ 119 @Override 120 public void exportExtensionData(JsonWriter writer) throws IOException { 121 writer.name(SAVED_REGISTERED_CLIENTS); 122 writer.beginArray(); 123 writeSavedRegisteredClients(writer); 124 writer.endArray(); 125 126 writer.name(RESOURCE_SETS); 127 writer.beginArray(); 128 writeResourceSets(writer); 129 writer.endArray(); 130 131 writer.name(PERMISSION_TICKETS); 132 writer.beginArray(); 133 writePermissionTickets(writer); 134 writer.endArray(); 135 136 writer.name(TOKEN_PERMISSIONS); 137 writer.beginArray(); 138 writeTokenPermissions(writer); 139 writer.endArray(); 140 } 141 142 /** 143 * @param writer 144 * @throws IOException 145 */ 146 private void writeTokenPermissions(JsonWriter writer) throws IOException { 147 for (OAuth2AccessTokenEntity token : tokenRepository.getAllAccessTokens()) { 148 if (!token.getPermissions().isEmpty()) { // skip tokens that don't have the permissions structure attached 149 writer.beginObject(); 150 writer.name(TOKEN_ID).value(token.getId()); 151 writer.name(PERMISSIONS); 152 writer.beginArray(); 153 for (Permission p : token.getPermissions()) { 154 writer.beginObject(); 155 writer.name(RESOURCE_SET).value(p.getResourceSet().getId()); 156 writer.name(SCOPES); 157 writer.beginArray(); 158 for (String s : p.getScopes()) { 159 writer.value(s); 160 } 161 writer.endArray(); 162 writer.endObject(); 163 } 164 writer.endArray(); 165 166 writer.endObject(); 167 } 168 } 169 } 170 171 /** 172 * @param writer 173 * @throws IOException 174 */ 175 private void writePermissionTickets(JsonWriter writer) throws IOException { 176 for (PermissionTicket ticket : permissionRepository.getAll()) { 177 writer.beginObject(); 178 179 writer.name(CLAIMS_SUPPLIED); 180 writer.beginArray(); 181 for (Claim claim : ticket.getClaimsSupplied()) { 182 writer.beginObject(); 183 184 writer.name(ISSUER); 185 writer.beginArray(); 186 for (String issuer : claim.getIssuer()) { 187 writer.value(issuer); 188 } 189 writer.endArray(); 190 writer.name(CLAIM_TOKEN_FORMAT); 191 writer.beginArray(); 192 for (String format : claim.getClaimTokenFormat()) { 193 writer.value(format); 194 } 195 writer.endArray(); 196 writer.name(CLAIM_TYPE).value(claim.getClaimType()); 197 writer.name(FRIENDLY_NAME).value(claim.getFriendlyName()); 198 writer.name(NAME).value(claim.getName()); 199 writer.name(VALUE).value(claim.getValue().toString()); 200 writer.endObject(); 201 } 202 writer.endArray(); 203 204 writer.name(EXPIRATION).value(toUTCString(ticket.getExpiration())); 205 206 writer.name(PERMISSION); 207 writer.beginObject(); 208 Permission p = ticket.getPermission(); 209 writer.name(RESOURCE_SET).value(p.getResourceSet().getId()); 210 writer.name(SCOPES); 211 writer.beginArray(); 212 for (String s : p.getScopes()) { 213 writer.value(s); 214 } 215 writer.endArray(); 216 writer.endObject(); 217 218 writer.name(TICKET).value(ticket.getTicket()); 219 220 writer.endObject(); 221 } 222 223 224 } 225 226 /** 227 * @param writer 228 * @throws IOException 229 */ 230 private void writeResourceSets(JsonWriter writer) throws IOException { 231 for (ResourceSet rs : resourceSetRepository.getAll()) { 232 writer.beginObject(); 233 writer.name(ID).value(rs.getId()); 234 writer.name(CLIENT_ID).value(rs.getClientId()); 235 writer.name(ICON_URI).value(rs.getIconUri()); 236 writer.name(NAME).value(rs.getName()); 237 writer.name(TYPE).value(rs.getType()); 238 writer.name(URI).value(rs.getUri()); 239 writer.name(OWNER).value(rs.getOwner()); 240 writer.name(POLICIES); 241 writer.beginArray(); 242 for (Policy policy : rs.getPolicies()) { 243 writer.beginObject(); 244 writer.name(NAME).value(policy.getName()); 245 writer.name(SCOPES); 246 writer.beginArray(); 247 for (String scope : policy.getScopes()) { 248 writer.value(scope); 249 } 250 writer.endArray(); 251 writer.name(CLAIMS_REQUIRED); 252 writer.beginArray(); 253 for (Claim claim : policy.getClaimsRequired()) { 254 writer.beginObject(); 255 256 writer.name(ISSUER); 257 writer.beginArray(); 258 for (String issuer : claim.getIssuer()) { 259 writer.value(issuer); 260 } 261 writer.endArray(); 262 writer.name(CLAIM_TOKEN_FORMAT); 263 writer.beginArray(); 264 for (String format : claim.getClaimTokenFormat()) { 265 writer.value(format); 266 } 267 writer.endArray(); 268 writer.name(CLAIM_TYPE).value(claim.getClaimType()); 269 writer.name(FRIENDLY_NAME).value(claim.getFriendlyName()); 270 writer.name(NAME).value(claim.getName()); 271 writer.name(VALUE).value(claim.getValue().toString()); 272 writer.endObject(); 273 } 274 writer.endArray(); 275 writer.endObject(); 276 } 277 writer.endArray(); 278 writer.name(SCOPES); 279 writer.beginArray(); 280 for (String scope : rs.getScopes()) { 281 writer.value(scope); 282 } 283 writer.endArray(); 284 writer.endObject(); 285 logger.debug("Finished writing resource set {}", rs.getId()); 286 } 287 288 } 289 290 /** 291 * @param writer 292 */ 293 private void writeSavedRegisteredClients(JsonWriter writer) throws IOException { 294 for (SavedRegisteredClient src : registeredClientService.getAll()) { 295 writer.beginObject(); 296 writer.name(ISSUER).value(src.getIssuer()); 297 writer.name(REGISTERED_CLIENT).value(src.getRegisteredClient().getSource().toString()); 298 writer.endObject(); 299 logger.debug("Wrote saved registered client {}", src.getId()); 300 } 301 logger.info("Done writing saved registered clients"); 302 } 303 304 /* (non-Javadoc) 305 * @see org.mitre.openid.connect.service.MITREidDataServiceExtension#importExtensionData(com.google.gson.stream.JsonReader) 306 */ 307 @Override 308 public boolean importExtensionData(String name, JsonReader reader) throws IOException { 309 if (name.equals(SAVED_REGISTERED_CLIENTS)) { 310 readSavedRegisteredClients(reader); 311 return true; 312 } else if (name.equals(RESOURCE_SETS)) { 313 readResourceSets(reader); 314 return true; 315 } else if (name.equals(PERMISSION_TICKETS)) { 316 readPermissionTickets(reader); 317 return true; 318 } else if (name.equals(TOKEN_PERMISSIONS)) { 319 readTokenPermissions(reader); 320 return true; 321 } else { 322 return false; 323 } 324 } 325 326 /** 327 * @param reader 328 */ 329 private void readTokenPermissions(JsonReader reader) throws IOException { 330 reader.beginArray(); 331 while(reader.hasNext()) { 332 reader.beginObject(); 333 Long tokenId = null; 334 Set<Long> permissions = new HashSet<>(); 335 while (reader.hasNext()) { 336 switch(reader.peek()) { 337 case END_OBJECT: 338 continue; 339 case NAME: 340 String name = reader.nextName(); 341 if (name.equals(TOKEN_ID)) { 342 tokenId = reader.nextLong(); 343 } else if (name.equals(PERMISSIONS)) { 344 reader.beginArray(); 345 while (reader.hasNext()) { 346 Permission p = new Permission(); 347 Long rsid = null; 348 Set<String> scope = new HashSet<>(); 349 reader.beginObject(); 350 while (reader.hasNext()) { 351 switch (reader.peek()) { 352 case END_OBJECT: 353 continue; 354 case NAME: 355 String pname = reader.nextName(); 356 if (reader.peek() == JsonToken.NULL) { 357 reader.skipValue(); 358 } else if (pname.equals(RESOURCE_SET)) { 359 rsid = reader.nextLong(); 360 } else if (pname.equals(SCOPES)) { 361 scope = readSet(reader); 362 } else { 363 logger.debug("Found unexpected entry"); 364 reader.skipValue(); 365 } 366 break; 367 default: 368 logger.debug("Found unexpected entry"); 369 reader.skipValue(); 370 continue; 371 } 372 } 373 reader.endObject(); 374 p.setScopes(scope); 375 Permission saved = permissionRepository.saveRawPermission(p); 376 permissionToResourceRefs.put(saved.getId(), rsid); 377 permissions.add(saved.getId()); 378 } 379 reader.endArray(); 380 } 381 break; 382 default: 383 logger.debug("Found unexpected entry"); 384 reader.skipValue(); 385 continue; 386 } 387 } 388 reader.endObject(); 389 tokenToPermissionRefs.put(tokenId, permissions); 390 } 391 reader.endArray(); 392 393 } 394 395 private Map<Long, Long> permissionToResourceRefs = new HashMap<>(); 396 397 /** 398 * @param reader 399 */ 400 private void readPermissionTickets(JsonReader reader) throws IOException { 401 JsonParser parser = new JsonParser(); 402 reader.beginArray(); 403 while (reader.hasNext()) { 404 PermissionTicket ticket = new PermissionTicket(); 405 reader.beginObject(); 406 while (reader.hasNext()) { 407 switch (reader.peek()) { 408 case END_OBJECT: 409 continue; 410 case NAME: 411 String name = reader.nextName(); 412 if (reader.peek() == JsonToken.NULL) { 413 reader.skipValue(); 414 } else if (name.equals(CLAIMS_SUPPLIED)) { 415 Set<Claim> claimsSupplied = new HashSet<>(); 416 reader.beginArray(); 417 while (reader.hasNext()) { 418 Claim c = new Claim(); 419 reader.beginObject(); 420 while (reader.hasNext()) { 421 switch (reader.peek()) { 422 case END_OBJECT: 423 continue; 424 case NAME: 425 String cname = reader.nextName(); 426 if (reader.peek() == JsonToken.NULL) { 427 reader.skipValue(); 428 } else if (cname.equals(ISSUER)) { 429 c.setIssuer(readSet(reader)); 430 } else if (cname.equals(CLAIM_TOKEN_FORMAT)) { 431 c.setClaimTokenFormat(readSet(reader)); 432 } else if (cname.equals(CLAIM_TYPE)) { 433 c.setClaimType(reader.nextString()); 434 } else if (cname.equals(FRIENDLY_NAME)) { 435 c.setFriendlyName(reader.nextString()); 436 } else if (cname.equals(NAME)) { 437 c.setName(reader.nextString()); 438 } else if (cname.equals(VALUE)) { 439 JsonElement e = parser.parse(reader.nextString()); 440 c.setValue(e); 441 } else { 442 logger.debug("Found unexpected entry"); 443 reader.skipValue(); 444 } 445 break; 446 default: 447 logger.debug("Found unexpected entry"); 448 reader.skipValue(); 449 continue; 450 } 451 } 452 reader.endObject(); 453 claimsSupplied.add(c); 454 } 455 reader.endArray(); 456 ticket.setClaimsSupplied(claimsSupplied); 457 } else if (name.equals(EXPIRATION)) { 458 ticket.setExpiration(utcToDate(reader.nextString())); 459 } else if (name.equals(PERMISSION)) { 460 Permission p = new Permission(); 461 Long rsid = null; 462 reader.beginObject(); 463 while (reader.hasNext()) { 464 switch (reader.peek()) { 465 case END_OBJECT: 466 continue; 467 case NAME: 468 String pname = reader.nextName(); 469 if (reader.peek() == JsonToken.NULL) { 470 reader.skipValue(); 471 } else if (pname.equals(RESOURCE_SET)) { 472 rsid = reader.nextLong(); 473 } else if (pname.equals(SCOPES)) { 474 p.setScopes(readSet(reader)); 475 } else { 476 logger.debug("Found unexpected entry"); 477 reader.skipValue(); 478 } 479 break; 480 default: 481 logger.debug("Found unexpected entry"); 482 reader.skipValue(); 483 continue; 484 } 485 } 486 reader.endObject(); 487 Permission saved = permissionRepository.saveRawPermission(p); 488 permissionToResourceRefs.put(saved.getId(), rsid); 489 ticket.setPermission(saved); 490 } else if (name.equals(TICKET)) { 491 ticket.setTicket(reader.nextString()); 492 } else { 493 logger.debug("Found unexpected entry"); 494 reader.skipValue(); 495 } 496 break; 497 default: 498 logger.debug("Found unexpected entry"); 499 reader.skipValue(); 500 continue; 501 } 502 } 503 reader.endObject(); 504 permissionRepository.save(ticket); 505 } 506 reader.endArray(); 507 } 508 509 510 private Map<Long, Long> resourceSetOldToNewIdMap = new HashMap<>(); 511 512 /** 513 * @param reader 514 */ 515 private void readResourceSets(JsonReader reader) throws IOException { 516 JsonParser parser = new JsonParser(); 517 reader.beginArray(); 518 while (reader.hasNext()) { 519 Long oldId = null; 520 ResourceSet rs = new ResourceSet(); 521 reader.beginObject(); 522 while (reader.hasNext()) { 523 switch (reader.peek()) { 524 case END_OBJECT: 525 continue; 526 case NAME: 527 String name = reader.nextName(); 528 if (reader.peek() == JsonToken.NULL) { 529 reader.skipValue(); 530 } else if (name.equals(ID)) { 531 oldId = reader.nextLong(); 532 } else if (name.equals(CLIENT_ID)) { 533 rs.setClientId(reader.nextString()); 534 } else if (name.equals(ICON_URI)) { 535 rs.setIconUri(reader.nextString()); 536 } else if (name.equals(NAME)) { 537 rs.setName(reader.nextString()); 538 } else if (name.equals(TYPE)) { 539 rs.setType(reader.nextString()); 540 } else if (name.equals(URI)) { 541 rs.setUri(reader.nextString()); 542 } else if (name.equals(OWNER)) { 543 rs.setOwner(reader.nextString()); 544 } else if (name.equals(POLICIES)) { 545 Set<Policy> policies = new HashSet<>(); 546 reader.beginArray(); 547 while (reader.hasNext()) { 548 Policy p = new Policy(); 549 reader.beginObject(); 550 while (reader.hasNext()) { 551 switch (reader.peek()) { 552 case END_OBJECT: 553 continue; 554 case NAME: 555 String pname = reader.nextName(); 556 if (reader.peek() == JsonToken.NULL) { 557 reader.skipValue(); 558 } else if (pname.equals(NAME)) { 559 p.setName(reader.nextString()); 560 } else if (pname.equals(SCOPES)) { 561 p.setScopes(readSet(reader)); 562 } else if (pname.equals(CLAIMS_REQUIRED)) { 563 Set<Claim> claimsRequired = new HashSet<>(); 564 reader.beginArray(); 565 while (reader.hasNext()) { 566 Claim c = new Claim(); 567 reader.beginObject(); 568 while (reader.hasNext()) { 569 switch (reader.peek()) { 570 case END_OBJECT: 571 continue; 572 case NAME: 573 String cname = reader.nextName(); 574 if (reader.peek() == JsonToken.NULL) { 575 reader.skipValue(); 576 } else if (cname.equals(ISSUER)) { 577 c.setIssuer(readSet(reader)); 578 } else if (cname.equals(CLAIM_TOKEN_FORMAT)) { 579 c.setClaimTokenFormat(readSet(reader)); 580 } else if (cname.equals(CLAIM_TYPE)) { 581 c.setClaimType(reader.nextString()); 582 } else if (cname.equals(FRIENDLY_NAME)) { 583 c.setFriendlyName(reader.nextString()); 584 } else if (cname.equals(NAME)) { 585 c.setName(reader.nextString()); 586 } else if (cname.equals(VALUE)) { 587 JsonElement e = parser.parse(reader.nextString()); 588 c.setValue(e); 589 } else { 590 logger.debug("Found unexpected entry"); 591 reader.skipValue(); 592 } 593 break; 594 default: 595 logger.debug("Found unexpected entry"); 596 reader.skipValue(); 597 continue; 598 } 599 } 600 reader.endObject(); 601 claimsRequired.add(c); 602 } 603 reader.endArray(); 604 p.setClaimsRequired(claimsRequired); 605 } else { 606 logger.debug("Found unexpected entry"); 607 reader.skipValue(); 608 } 609 break; 610 default: 611 logger.debug("Found unexpected entry"); 612 reader.skipValue(); 613 continue; 614 } 615 } 616 reader.endObject(); 617 policies.add(p); 618 } 619 reader.endArray(); 620 rs.setPolicies(policies); 621 } else if (name.equals(SCOPES)) { 622 rs.setScopes(readSet(reader)); 623 } else { 624 logger.debug("Found unexpected entry"); 625 reader.skipValue(); 626 } 627 break; 628 default: 629 logger.debug("Found unexpected entry"); 630 reader.skipValue(); 631 continue; 632 } 633 } 634 reader.endObject(); 635 Long newId = resourceSetRepository.save(rs).getId(); 636 resourceSetOldToNewIdMap.put(oldId, newId); 637 } 638 reader.endArray(); 639 logger.info("Done reading resource sets"); 640 } 641 642 /** 643 * @param reader 644 */ 645 private void readSavedRegisteredClients(JsonReader reader) throws IOException{ 646 reader.beginArray(); 647 while (reader.hasNext()) { 648 String issuer = null; 649 String clientString = null; 650 reader.beginObject(); 651 while (reader.hasNext()) { 652 switch (reader.peek()) { 653 case END_OBJECT: 654 continue; 655 case NAME: 656 String name = reader.nextName(); 657 if (reader.peek() == JsonToken.NULL) { 658 reader.skipValue(); 659 } else if (name.equals(ISSUER)) { 660 issuer = reader.nextString(); 661 } else if (name.equals(REGISTERED_CLIENT)) { 662 clientString = reader.nextString(); 663 } else { 664 logger.debug("Found unexpected entry"); 665 reader.skipValue(); 666 } 667 break; 668 default: 669 logger.debug("Found unexpected entry"); 670 reader.skipValue(); 671 continue; 672 } 673 } 674 reader.endObject(); 675 RegisteredClient client = ClientDetailsEntityJsonProcessor.parseRegistered(clientString); 676 registeredClientService.save(issuer, client); 677 logger.debug("Saved registered client"); 678 } 679 reader.endArray(); 680 logger.info("Done reading saved registered clients"); 681 } 682 683 /* (non-Javadoc) 684 * @see org.mitre.openid.connect.service.MITREidDataServiceExtension#fixExtensionObjectReferences() 685 */ 686 @Override 687 public void fixExtensionObjectReferences(MITREidDataServiceMaps maps) { 688 for (Long permissionId : permissionToResourceRefs.keySet()) { 689 Long oldResourceId = permissionToResourceRefs.get(permissionId); 690 Long newResourceId = resourceSetOldToNewIdMap.get(oldResourceId); 691 Permission p = permissionRepository.getById(permissionId); 692 ResourceSet rs = resourceSetRepository.getById(newResourceId); 693 p.setResourceSet(rs); 694 permissionRepository.saveRawPermission(p); 695 logger.debug("Mapping rsid " + oldResourceId + " to " + newResourceId + " for permission " + permissionId); 696 } 697 for (Long tokenId : tokenToPermissionRefs.keySet()) { 698 Long newTokenId = maps.getAccessTokenOldToNewIdMap().get(tokenId); 699 OAuth2AccessTokenEntity token = tokenRepository.getAccessTokenById(newTokenId); 700 701 Set<Permission> permissions = new HashSet<>(); 702 for (Long permissionId : tokenToPermissionRefs.get(tokenId)) { 703 Permission p = permissionRepository.getById(permissionId); 704 permissions.add(p); 705 } 706 707 token.setPermissions(permissions); 708 tokenRepository.saveAccessToken(token); 709 } 710 permissionToResourceRefs.clear(); 711 resourceSetOldToNewIdMap.clear(); 712 tokenToPermissionRefs.clear(); 713 } 714 715}