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.token; 019 020 021import java.util.List; 022import java.util.Map; 023 024import net.jcip.annotations.Immutable; 025import net.minidev.json.JSONObject; 026 027import com.nimbusds.oauth2.sdk.ParseException; 028import com.nimbusds.oauth2.sdk.Scope; 029import com.nimbusds.oauth2.sdk.http.HTTPRequest; 030 031 032/** 033 * DPoP access token. 034 * 035 * <p>Example DPoP access token serialised to JSON: 036 * 037 * <pre> 038 * { 039 * "access_token" : "aeniniu3oogh2quoot7Aipie9IeGh3te", 040 * "token_type" : "DPoP", 041 * "expires_in" : 3600, 042 * "scope" : "read write" 043 * } 044 * </pre> 045 * 046 * <p>The above example token serialised to a HTTP Authorization header: 047 * 048 * <pre> 049 * Authorization: DPoP aeniniu3oogh2quoot7Aipie9IeGh3te 050 * </pre> 051 * 052 * <p>Related specifications: 053 * 054 * <ul> 055 * <li>OAuth 2.0 (RFC 6749), sections 1.4 and 5.1. 056 * <li>OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer 057 * (DPoP) (draft-ietf-oauth-dpop-03) 058 * <li>OAuth 2.0 Token Exchange (RFC 8693), section 3. 059 * </ul> 060 */ 061@Immutable 062public class DPoPAccessToken extends AccessToken { 063 064 065 private static final long serialVersionUID = 7745184045632691024L; 066 067 068 /** 069 * Creates a new minimal DPoP access token with the specified value. 070 * The optional lifetime, scope and token type URI are left 071 * unspecified. 072 * 073 * @param value The access token value. Must not be {@code null} or 074 * empty string. 075 */ 076 public DPoPAccessToken(final String value) { 077 078 this(value, 0L, null); 079 } 080 081 082 /** 083 * Creates a new DPoP access token with the specified value. The 084 * optional token type URI is left unspecified. 085 * 086 * @param value The access token value. Must not be {@code null} or 087 * empty string. 088 * @param lifetime The lifetime in seconds, 0 if not specified. 089 * @param scope The scope, {@code null} if not specified. 090 */ 091 public DPoPAccessToken(final String value, final long lifetime, final Scope scope) { 092 093 this(value, lifetime, scope, null); 094 } 095 096 /** 097 * Creates a new DPoP access token with the specified value. 098 * 099 * @param value The access token value. Must not be 100 * {@code null} or empty string. 101 * @param lifetime The lifetime in seconds, 0 if not specified. 102 * @param scope The scope, {@code null} if not specified. 103 * @param issuedTokenType The token type URI, {@code null} if not 104 * specified. 105 */ 106 public DPoPAccessToken(final String value, final long lifetime, final Scope scope, final TokenTypeURI issuedTokenType) { 107 108 super(AccessTokenType.DPOP, value, lifetime, scope, issuedTokenType); 109 } 110 111 112 /** 113 * Returns the HTTP Authorization header value for this DPoP access 114 * token. 115 * 116 * <p>Example: 117 * 118 * <pre> 119 * Authorization: DPoP aeniniu3oogh2quoot7Aipie9IeGh3te 120 * </pre> 121 * 122 * @return The HTTP Authorization header. 123 */ 124 @Override 125 public String toAuthorizationHeader(){ 126 127 return "DPoP " + getValue(); 128 } 129 130 131 @Override 132 public boolean equals(final Object object) { 133 134 return object instanceof DPoPAccessToken && 135 this.toString().equals(object.toString()); 136 } 137 138 139 /** 140 * Parses a DPoP access token from a JSON object access token 141 * response. 142 * 143 * @param jsonObject The JSON object to parse. Must not be 144 * {@code null}. 145 * 146 * @return The DPoP access token. 147 * 148 * @throws ParseException If the JSON object couldn't be parsed to a 149 * DPoP access token. 150 */ 151 public static DPoPAccessToken parse(final JSONObject jsonObject) 152 throws ParseException { 153 154 AccessTokenUtils.parseAndEnsureType(jsonObject, AccessTokenType.DPOP); 155 String accessTokenValue = AccessTokenUtils.parseValue(jsonObject); 156 long lifetime = AccessTokenUtils.parseLifetime(jsonObject); 157 Scope scope = AccessTokenUtils.parseScope(jsonObject); 158 TokenTypeURI issuedTokenType = AccessTokenUtils.parseIssuedTokenType(jsonObject); 159 return new DPoPAccessToken(accessTokenValue, lifetime, scope, issuedTokenType); 160 } 161 162 163 /** 164 * Parses an HTTP Authorization header for a DPoP access token. 165 * 166 * @param header The HTTP Authorization header value to parse. May be 167 * {@code null} if the header is missing, in which case 168 * an exception will be thrown. 169 * 170 * @return The DPoP access token. 171 * 172 * @throws ParseException If the HTTP Authorization header value 173 * couldn't be parsed to a DPoP access token. 174 */ 175 public static DPoPAccessToken parse(final String header) 176 throws ParseException { 177 178 return new DPoPAccessToken(AccessTokenUtils.parseValueFromHeader(header, AccessTokenType.DPOP)); 179 } 180 181 182 /** 183 * Parses a query or form parameters map for a bearer access token. 184 * 185 * @param parameters The query parameters. Must not be {@code null}. 186 * 187 * @return The bearer access token. 188 * 189 * @throws ParseException If a bearer access token wasn't found in the 190 * parameters. 191 */ 192 public static DPoPAccessToken parse(final Map<String,List<String>> parameters) 193 throws ParseException { 194 195 return new DPoPAccessToken(AccessTokenUtils.parseValueFromQueryParameters(parameters, AccessTokenType.DPOP)); 196 } 197 198 199 200 /** 201 * Parses an HTTP request for a bearer access token. 202 * 203 * @param request The HTTP request to parse. Must not be {@code null}. 204 * 205 * @return The bearer access token. 206 * 207 * @throws ParseException If a bearer access token wasn't found in the 208 * HTTP request. 209 */ 210 public static DPoPAccessToken parse(final HTTPRequest request) 211 throws ParseException { 212 213 // See http://tools.ietf.org/html/rfc6750#section-2 214 String authzHeader = request.getAuthorization(); 215 216 if (authzHeader != null) { 217 return parse(authzHeader); 218 } 219 220 // Try alternative token locations, form and query string are 221 // parameters are not differentiated here 222 Map<String,List<String>> params = request.getQueryParameters(); 223 return parse(params); 224 } 225}