001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2016, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.oauth2.sdk; 019 020 021import com.nimbusds.common.contenttype.ContentType; 022import com.nimbusds.jose.util.Base64URL; 023import com.nimbusds.jwt.util.DateUtils; 024import com.nimbusds.oauth2.sdk.auth.X509CertificateConfirmation; 025import com.nimbusds.oauth2.sdk.dpop.JWKThumbprintConfirmation; 026import com.nimbusds.oauth2.sdk.http.HTTPResponse; 027import com.nimbusds.oauth2.sdk.id.*; 028import com.nimbusds.oauth2.sdk.rar.AuthorizationDetail; 029import com.nimbusds.oauth2.sdk.token.AccessTokenType; 030import com.nimbusds.oauth2.sdk.util.JSONArrayUtils; 031import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 032import com.nimbusds.openid.connect.sdk.claims.ACR; 033import net.jcip.annotations.Immutable; 034import net.minidev.json.JSONArray; 035import net.minidev.json.JSONObject; 036 037import java.util.Date; 038import java.util.List; 039import java.util.Map; 040 041 042/** 043 * Token introspection success response. 044 * 045 * <p>Related specifications: 046 * 047 * <ul> 048 * <li>OAuth 2.0 Token Introspection (RFC 7662) 049 * <li>OAuth 2.0 Rich Authorization Requests (RFC 9396) 050 * <li>OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound 051 * Access Tokens (RFC 8705) 052 * <li>OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer 053 * (DPoP) (RFC 9449) 054 * <li>OAuth 2.0 Step Up Authentication Challenge Protocol (RFC 9470) 055 * </ul> 056 */ 057@Immutable 058public class TokenIntrospectionSuccessResponse extends TokenIntrospectionResponse implements SuccessResponse { 059 060 061 /** 062 * Builder for constructing token introspection success responses. 063 */ 064 public static class Builder { 065 066 067 /** 068 * The parameters. 069 */ 070 private final JSONObject params = new JSONObject(); 071 072 073 /** 074 * Creates a new token introspection success response builder. 075 * 076 * @param active {@code true} if the token is active, else 077 * {@code false}. 078 */ 079 public Builder(final boolean active) { 080 081 params.put("active", active); 082 } 083 084 085 /** 086 * Creates a new token introspection success response builder 087 * with the parameters of the specified response. 088 * 089 * @param response The response which parameters to use. Not 090 * {@code null}. 091 */ 092 public Builder(final TokenIntrospectionSuccessResponse response) { 093 094 params.putAll(response.params); 095 } 096 097 098 /** 099 * Sets the token scope. Corresponds to the {@code scope} 100 * parameter. 101 * 102 * @param scope The token scope, {@code null} if not specified. 103 * 104 * @return This builder. 105 */ 106 public Builder scope(final Scope scope) { 107 if (scope != null) params.put("scope", scope.toString()); 108 else params.remove("scope"); 109 return this; 110 } 111 112 113 /** 114 * Sets the identifier for the OAuth 2.0 client that requested 115 * the token. Corresponds to the {@code client_id} parameter. 116 * 117 * @param clientID The client identifier, {@code null} if not 118 * specified. 119 * 120 * @return This builder. 121 */ 122 public Builder clientID(final ClientID clientID) { 123 if (clientID != null) params.put("client_id", clientID.getValue()); 124 else params.remove("client_id"); 125 return this; 126 } 127 128 129 /** 130 * Sets the username of the resource owner who authorised the 131 * token. Corresponds to the {@code username} parameter. 132 * 133 * @param username The username, {@code null} if not specified. 134 * 135 * @return This builder. 136 */ 137 public Builder username(final String username) { 138 if (username != null) params.put("username", username); 139 else params.remove("username"); 140 return this; 141 } 142 143 144 /** 145 * Sets the token type. Corresponds to the {@code token_type} 146 * parameter. 147 * 148 * @param tokenType The token type, {@code null} if not 149 * specified. 150 * 151 * @return This builder. 152 */ 153 public Builder tokenType(final AccessTokenType tokenType) { 154 if (tokenType != null) params.put("token_type", tokenType.getValue()); 155 else params.remove("token_type"); 156 return this; 157 } 158 159 160 /** 161 * Sets the token expiration time. Corresponds to the 162 * {@code exp} parameter. 163 * 164 * @param exp The token expiration time, {@code null} if not 165 * specified. 166 * 167 * @return This builder. 168 */ 169 public Builder expirationTime(final Date exp) { 170 if (exp != null) params.put("exp", DateUtils.toSecondsSinceEpoch(exp)); 171 else params.remove("exp"); 172 return this; 173 } 174 175 176 /** 177 * Sets the token issue time. Corresponds to the {@code iat} 178 * parameter. 179 * 180 * @param iat The token issue time, {@code null} if not 181 * specified. 182 * 183 * @return This builder. 184 */ 185 public Builder issueTime(final Date iat) { 186 if (iat != null) params.put("iat", DateUtils.toSecondsSinceEpoch(iat)); 187 else params.remove("iat"); 188 return this; 189 } 190 191 192 /** 193 * Sets the token not-before time. Corresponds to the 194 * {@code nbf} parameter. 195 * 196 * @param nbf The token not-before time, {@code null} if not 197 * specified. 198 * 199 * @return This builder. 200 */ 201 public Builder notBeforeTime(final Date nbf) { 202 if (nbf != null) params.put("nbf", DateUtils.toSecondsSinceEpoch(nbf)); 203 else params.remove("nbf"); 204 return this; 205 } 206 207 208 /** 209 * Sets the token subject. Corresponds to the {@code sub} 210 * parameter. 211 * 212 * @param sub The token subject, {@code null} if not specified. 213 * 214 * @return This builder. 215 */ 216 public Builder subject(final Subject sub) { 217 if (sub != null) params.put("sub", sub.getValue()); 218 else params.remove("sub"); 219 return this; 220 } 221 222 223 /** 224 * Sets the token audience. Corresponds to the {@code aud} 225 * parameter. 226 * 227 * @param audList The token audience, {@code null} if not 228 * specified. 229 * 230 * @return This builder. 231 */ 232 public Builder audience(final List<Audience> audList) { 233 if (audList != null) params.put("aud", Audience.toStringList(audList)); 234 else params.remove("aud"); 235 return this; 236 } 237 238 239 /** 240 * Sets the token issuer. Corresponds to the {@code iss} 241 * parameter. 242 * 243 * @param iss The token issuer, {@code null} if not specified. 244 * 245 * @return This builder. 246 */ 247 public Builder issuer(final Issuer iss) { 248 if (iss != null) params.put("iss", iss.getValue()); 249 else params.remove("iss"); 250 return this; 251 } 252 253 254 /** 255 * Sets the token identifier. Corresponds to the {@code jti} 256 * parameter. 257 * 258 * @param jti The token identifier, {@code null} if not 259 * specified. 260 * 261 * @return This builder. 262 */ 263 public Builder jwtID(final JWTID jti) { 264 if (jti != null) params.put("jti", jti.getValue()); 265 else params.remove("jti"); 266 return this; 267 } 268 269 270 /** 271 * Sets the client X.509 certificate SHA-256 thumbprint, for a 272 * mutual TLS client certificate bound access token. 273 * Corresponds to the {@code cnf.x5t#S256} parameter. 274 * 275 * @param x5t The client X.509 certificate SHA-256 thumbprint, 276 * {@code null} if not specified. 277 * 278 * @return This builder. 279 */ 280 @Deprecated 281 public Builder x509CertificateSHA256Thumbprint(final Base64URL x5t) { 282 283 if (x5t != null) { 284 JSONObject cnf; 285 if (params.containsKey("cnf")) { 286 cnf = (JSONObject)params.get("cnf"); 287 } else { 288 cnf = new JSONObject(); 289 params.put("cnf", cnf); 290 } 291 cnf.put("x5t#S256", x5t.toString()); 292 } else if (params.containsKey("cnf")) { 293 JSONObject cnf = (JSONObject) params.get("cnf"); 294 cnf.remove("x5t#S256"); 295 if (cnf.isEmpty()) { 296 params.remove("cnf"); 297 } 298 } 299 300 return this; 301 } 302 303 304 /** 305 * Sets the client X.509 certificate confirmation, for a mutual 306 * TLS client certificate bound access token. Corresponds to 307 * the {@code cnf.x5t#S256} parameter. 308 * 309 * @param cnf The client X.509 certificate confirmation, 310 * {@code null} if not specified. 311 * 312 * @return This builder. 313 */ 314 public Builder x509CertificateConfirmation(final X509CertificateConfirmation cnf) { 315 316 if (cnf != null) { 317 Map.Entry<String, JSONObject> param = cnf.toJWTClaim(); 318 params.put(param.getKey(), param.getValue()); 319 } else { 320 params.remove("cnf"); 321 } 322 return this; 323 } 324 325 326 /** 327 * Sets the JSON Web Key (JWK) SHA-256 thumbprint confirmation, 328 * for OAuth 2.0 DPoP. Corresponds to the {@code cnf.jkt} 329 * parameter. 330 * 331 * @param cnf The JWK SHA-256 thumbprint confirmation, 332 * {@code null} if not specified. 333 * 334 * @return This builder. 335 */ 336 public Builder jwkThumbprintConfirmation(final JWKThumbprintConfirmation cnf) { 337 338 if (cnf != null) { 339 Map.Entry<String, JSONObject> param = cnf.toJWTClaim(); 340 params.put(param.getKey(), param.getValue()); 341 } else { 342 params.remove("cnf"); 343 } 344 return this; 345 } 346 347 348 /** 349 * Sets the Rich Authorisation Request (RAR) details. 350 * Corresponds to the {@code authorization_details} parameter. 351 * 352 * @param authorizationDetails The authorisation details, 353 * {@code null} if not specified. 354 * 355 * @return This builder. 356 */ 357 public Builder authorizationDetails(final List<AuthorizationDetail> authorizationDetails) { 358 359 if (authorizationDetails != null) { 360 JSONArray jsonArray = AuthorizationDetail.toJSONArray(authorizationDetails); 361 params.put("authorization_details", jsonArray); 362 } else { 363 params.remove("authorization_details"); 364 } 365 return this; 366 } 367 368 369 /** 370 * Sets the Authentication Context Class Reference (ACR). 371 * Corresponds to the {@code acr} parameter. 372 * 373 * @param acr The ACR value, {@code null} if not specified. 374 * 375 * @return This builder. 376 */ 377 public Builder acr(final ACR acr) { 378 if (acr != null) params.put("acr", acr.getValue()); 379 else params.remove("acr"); 380 return this; 381 } 382 383 384 /** 385 * Sets the subject authentication time. Corresponds to the 386 * {@code auth_time} parameter. 387 * 388 * @param authTime The authentication time, {@code null} if not 389 * specified. 390 * 391 * @return This builder. 392 */ 393 public Builder authenticationTime(final Date authTime) { 394 if (authTime != null) params.put("auth_time", DateUtils.toSecondsSinceEpoch(authTime)); 395 else params.remove("auth_time"); 396 return this; 397 } 398 399 400 /** 401 * Sets a custom parameter. 402 * 403 * @param name The parameter name. Must not be {@code null}. 404 * @param value The parameter value. Should map to a JSON type. 405 * If {@code null} not specified. 406 * 407 * @return This builder. 408 */ 409 public Builder parameter(final String name, final Object value) { 410 if (value != null) params.put(name, value); 411 else params.remove(name); 412 return this; 413 } 414 415 416 /** 417 * Builds a new token introspection success response. 418 * 419 * @return The token introspection success response. 420 */ 421 public TokenIntrospectionSuccessResponse build() { 422 423 return new TokenIntrospectionSuccessResponse(params); 424 } 425 } 426 427 428 /** 429 * The parameters. 430 */ 431 private final JSONObject params; 432 433 434 /** 435 * Creates a new token introspection success response. 436 * 437 * @param params The response parameters. Must contain at least the 438 * required {@code active} parameter and not be 439 * {@code null}. 440 */ 441 public TokenIntrospectionSuccessResponse(final JSONObject params) { 442 443 if (! (params.get("active") instanceof Boolean)) { 444 throw new IllegalArgumentException("Missing / invalid boolean active parameter"); 445 } 446 447 this.params = params; 448 } 449 450 451 /** 452 * Returns the active status for the token. Corresponds to the 453 * {@code active} parameter. 454 * 455 * @return {@code true} if the token is active, else {@code false}. 456 */ 457 public boolean isActive() { 458 459 try { 460 return JSONObjectUtils.getBoolean(params, "active", false); 461 } catch (ParseException e) { 462 return false; // always false on error 463 } 464 } 465 466 467 /** 468 * Returns the scope of the token. Corresponds to the {@code scope} 469 * parameter. 470 * 471 * @return The token scope, {@code null} if not specified. 472 */ 473 public Scope getScope() { 474 475 try { 476 return Scope.parse(JSONObjectUtils.getString(params, "scope")); 477 } catch (ParseException e) { 478 return null; 479 } 480 } 481 482 483 /** 484 * Returns the identifier of the OAuth 2.0 client that requested the 485 * token. Corresponds to the {@code client_id} parameter. 486 * 487 * @return The client identifier, {@code null} if not specified. 488 */ 489 public ClientID getClientID() { 490 491 try { 492 return new ClientID(JSONObjectUtils.getNonBlankString(params, "client_id")); 493 } catch (ParseException e) { 494 return null; 495 } 496 } 497 498 499 /** 500 * Returns the username of the resource owner who authorised the token. 501 * Corresponds to the {@code username} parameter. 502 * 503 * @return The username, {@code null} if not specified. 504 */ 505 public String getUsername() { 506 507 try { 508 return JSONObjectUtils.getString(params, "username", null); 509 } catch (ParseException e) { 510 return null; 511 } 512 } 513 514 515 /** 516 * Returns the access token type. Corresponds to the {@code token_type} 517 * parameter. 518 * 519 * @return The token type, {@code null} if not specified. 520 */ 521 public AccessTokenType getTokenType() { 522 523 try { 524 return new AccessTokenType(JSONObjectUtils.getNonBlankString(params, "token_type")); 525 } catch (ParseException e) { 526 return null; 527 } 528 } 529 530 531 /** 532 * Returns the token expiration time. Corresponds to the {@code exp} 533 * parameter. 534 * 535 * @return The token expiration time, {@code null} if not specified. 536 */ 537 public Date getExpirationTime() { 538 539 try { 540 return DateUtils.fromSecondsSinceEpoch(JSONObjectUtils.getNonNegativeLong(params, "exp")); 541 } catch (ParseException e) { 542 return null; 543 } 544 } 545 546 547 /** 548 * Returns the token issue time. Corresponds to the {@code iat} 549 * parameter. 550 * 551 * @return The token issue time, {@code null} if not specified. 552 */ 553 public Date getIssueTime() { 554 555 try { 556 return DateUtils.fromSecondsSinceEpoch(JSONObjectUtils.getNonNegativeLong(params, "iat")); 557 } catch (ParseException e) { 558 return null; 559 } 560 } 561 562 563 /** 564 * Returns the token not-before time. Corresponds to the {@code nbf} 565 * parameter. 566 * 567 * @return The token not-before time, {@code null} if not specified. 568 */ 569 public Date getNotBeforeTime() { 570 571 try { 572 return DateUtils.fromSecondsSinceEpoch(JSONObjectUtils.getNonNegativeLong(params, "nbf")); 573 } catch (ParseException e) { 574 return null; 575 } 576 } 577 578 579 /** 580 * Returns the subject of the token, usually a machine-readable 581 * identifier of the resource owner who authorised the token. 582 * Corresponds to the {@code sub} parameter. 583 * 584 * @return The token subject, {@code null} if not specified. 585 */ 586 public Subject getSubject() { 587 588 try { 589 return new Subject(JSONObjectUtils.getNonBlankString(params, "sub")); 590 } catch (ParseException e) { 591 return null; 592 } 593 } 594 595 596 /** 597 * Returns the intended audience for the token. Corresponds to the 598 * {@code aud} parameter. 599 * 600 * @return The token audience, {@code null} if not specified. 601 */ 602 public List<Audience> getAudience() { 603 // Try string array first, then string 604 try { 605 return Audience.create(JSONObjectUtils.getStringList(params, "aud")); 606 } catch (ParseException e) { 607 try { 608 return new Audience(JSONObjectUtils.getNonBlankString(params, "aud")).toSingleAudienceList(); 609 } catch (ParseException e2) { 610 return null; 611 } 612 } 613 } 614 615 616 /** 617 * Returns the token issuer. Corresponds to the {@code iss} parameter. 618 * 619 * @return The token issuer, {@code null} if not specified. 620 */ 621 public Issuer getIssuer() { 622 623 try { 624 return new Issuer(JSONObjectUtils.getNonBlankString(params, "iss")); 625 } catch (ParseException e) { 626 return null; 627 } 628 } 629 630 631 /** 632 * Returns the token identifier. Corresponds to the {@code jti} 633 * parameter. 634 * 635 * @return The token identifier, {@code null} if not specified. 636 */ 637 public JWTID getJWTID() { 638 639 try { 640 return new JWTID(JSONObjectUtils.getNonBlankString(params, "jti")); 641 } catch (ParseException e) { 642 return null; 643 } 644 } 645 646 647 /** 648 * Returns the client X.509 certificate SHA-256 thumbprint, for a 649 * mutual TLS client certificate bound access token. Corresponds to the 650 * {@code cnf.x5t#S256} parameter. 651 * 652 * @return The client X.509 certificate SHA-256 thumbprint, 653 * {@code null} if not specified. 654 */ 655 @Deprecated 656 public Base64URL getX509CertificateSHA256Thumbprint() { 657 658 try { 659 JSONObject cnf = JSONObjectUtils.getJSONObject(params, "cnf", null); 660 661 if (cnf == null) return null; 662 663 String x5t = JSONObjectUtils.getString(cnf, "x5t#S256", null); 664 665 if (x5t == null) return null; 666 667 return new Base64URL(x5t); 668 669 } catch (ParseException e) { 670 return null; 671 } 672 } 673 674 675 /** 676 * Returns the client X.509 certificate confirmation, for a mutual TLS 677 * client certificate bound access token. Corresponds to the 678 * {@code cnf.x5t#S256} parameter. 679 * 680 * @return The client X.509 certificate confirmation, {@code null} if 681 * not specified. 682 */ 683 public X509CertificateConfirmation getX509CertificateConfirmation() { 684 685 return X509CertificateConfirmation.parse(params); 686 } 687 688 689 /** 690 * Returns the JSON Web Key (JWK) SHA-256 thumbprint confirmation, for 691 * OAuth 2.0 DPoP. Corresponds to the {@code cnf.jkt} parameter. 692 * 693 * @return The JWK SHA-256 thumbprint confirmation, {@code null} if not 694 * specified. 695 */ 696 public JWKThumbprintConfirmation getJWKThumbprintConfirmation() { 697 698 return JWKThumbprintConfirmation.parse(params); 699 } 700 701 702 /** 703 * Returns the Rich Authorisation Request (RAR) details. Corresponds to 704 * the {@code authorization_details} parameter. 705 * 706 * @return The authorisation details, {@code null} if not specified. 707 */ 708 public List<AuthorizationDetail> getAuthorizationDetails() { 709 710 JSONArray jsonArray = getJSONArrayParameter("authorization_details"); 711 712 if (jsonArray == null) return null; 713 714 try { 715 return AuthorizationDetail.parseList(JSONArrayUtils.toJSONObjectList(jsonArray)); 716 } catch (ParseException e) { 717 return null; 718 } 719 } 720 721 722 /** 723 * Returns the Authentication Context Class Reference (ACR). 724 * Corresponds to the {@code acr} parameter. 725 * 726 * @return The ACR value, {@code null} if not specified or if parsing 727 * failed. 728 */ 729 public ACR getACR() { 730 731 try { 732 return new ACR(JSONObjectUtils.getNonBlankString(params, "acr")); 733 } catch (ParseException e) { 734 return null; 735 } 736 } 737 738 739 /** 740 * Returns the subject authentication time. Corresponds to the 741 * {@code auth_time} parameter. 742 * 743 * @return The authentication time, {@code null} if not specified or if 744 * parsing failed. 745 */ 746 public Date getAuthenticationTime() { 747 748 try { 749 return DateUtils.fromSecondsSinceEpoch(JSONObjectUtils.getNonNegativeLong(params, "auth_time")); 750 } catch (ParseException e) { 751 return null; 752 } 753 } 754 755 756 /** 757 * Returns the string parameter with the specified name. 758 * 759 * @param name The parameter name. Must not be {@code null}. 760 * 761 * @return The parameter value, {@code null} if not specified or if 762 * parsing failed. 763 */ 764 public String getStringParameter(final String name) { 765 766 try { 767 return JSONObjectUtils.getString(params, name, null); 768 } catch (ParseException e) { 769 return null; 770 } 771 } 772 773 774 /** 775 * Returns the boolean parameter with the specified name. 776 * 777 * @param name The parameter name. Must not be {@code null}. 778 * 779 * @return The parameter value. 780 * 781 * @throws ParseException If the parameter isn't specified or parsing 782 * failed. 783 */ 784 public boolean getBooleanParameter(final String name) 785 throws ParseException { 786 787 return JSONObjectUtils.getBoolean(params, name); 788 } 789 790 791 /** 792 * Returns the number parameter with the specified name. 793 * 794 * @param name The parameter name. Must not be {@code null}. 795 * 796 * @return The parameter value, {@code null} if not specified or 797 * parsing failed. 798 */ 799 public Number getNumberParameter(final String name) { 800 801 try { 802 return JSONObjectUtils.getNumber(params, name, null); 803 } catch (ParseException e) { 804 return null; 805 } 806 } 807 808 809 /** 810 * Returns the string list parameter with the specified name. 811 * 812 * @param name The parameter name. Must not be {@code null}. 813 * 814 * @return The parameter value, {@code null} if not specified or if 815 * parsing failed. 816 */ 817 public List<String> getStringListParameter(final String name) { 818 819 try { 820 return JSONObjectUtils.getStringList(params, name, null); 821 } catch (ParseException e) { 822 return null; 823 } 824 } 825 826 827 /** 828 * Returns the JSON object parameter with the specified name. 829 * 830 * @param name The parameter name. Must not be {@code null}. 831 * 832 * @return The parameter value, {@code null} if not specified or if 833 * parsing failed. 834 */ 835 public JSONObject getJSONObjectParameter(final String name) { 836 837 try { 838 return JSONObjectUtils.getJSONObject(params, name, null); 839 } catch (ParseException e) { 840 return null; 841 } 842 } 843 844 845 /** 846 * Returns the JSON array parameter with the specified name. 847 * 848 * @param name The parameter name. Must not be {@code null}. 849 * 850 * @return The parameter value, {@code null} if not specified or if 851 * parsing failed. 852 */ 853 public JSONArray getJSONArrayParameter(final String name) { 854 855 try { 856 return JSONObjectUtils.getJSONArray(params, name, null); 857 } catch (ParseException e) { 858 return null; 859 } 860 } 861 862 863 /** 864 * Returns the underlying parameters. 865 * 866 * @return The parameters, as JSON object. 867 */ 868 public JSONObject getParameters() { 869 870 return params; 871 } 872 873 874 /** 875 * Returns a JSON object representation of this token introspection 876 * success response. 877 * 878 * <p>Example JSON object: 879 * 880 * <pre> 881 * { 882 * "active" : true, 883 * "client_id" : "l238j323ds-23ij4", 884 * "username" : "jdoe", 885 * "scope" : "read write dolphin", 886 * "sub" : "Z5O3upPC88QrAjx00dis", 887 * "aud" : "https://protected.example.net/resource", 888 * "iss" : "https://server.example.com/", 889 * "exp" : 1419356238, 890 * "iat" : 1419350238, 891 * "extension_field" : "twenty-seven" 892 * } 893 * </pre> 894 * 895 * @return The JSON object. 896 */ 897 public JSONObject toJSONObject() { 898 899 return new JSONObject(params); 900 } 901 902 903 @Override 904 public boolean indicatesSuccess() { 905 906 return true; 907 } 908 909 910 @Override 911 public HTTPResponse toHTTPResponse() { 912 913 HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK); 914 httpResponse.setEntityContentType(ContentType.APPLICATION_JSON); 915 httpResponse.setBody(params.toJSONString()); 916 return httpResponse; 917 } 918 919 920 /** 921 * Parses a token introspection success response from the specified 922 * JSON object. 923 * 924 * @param jsonObject The JSON object to parse. Must not be {@code null}. 925 * 926 * @return The token introspection success response. 927 * 928 * @throws ParseException If the JSON object couldn't be parsed to a 929 * token introspection success response. 930 */ 931 public static TokenIntrospectionSuccessResponse parse(final JSONObject jsonObject) 932 throws ParseException { 933 934 try { 935 return new TokenIntrospectionSuccessResponse(jsonObject); 936 } catch (IllegalArgumentException e) { 937 throw new ParseException(e.getMessage(), e); 938 } 939 } 940 941 942 /** 943 * Parses a token introspection success response from the specified 944 * HTTP response. 945 * 946 * @param httpResponse The HTTP response. Must not be {@code null}. 947 * 948 * @return The token introspection success response. 949 * 950 * @throws ParseException If the HTTP response couldn't be parsed to a 951 * token introspection success response. 952 */ 953 public static TokenIntrospectionSuccessResponse parse(final HTTPResponse httpResponse) 954 throws ParseException { 955 956 httpResponse.ensureStatusCode(HTTPResponse.SC_OK); 957 JSONObject jsonObject = httpResponse.getBodyAsJSONObject(); 958 return parse(jsonObject); 959 } 960}