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 Demonstrating Proof-of-Possession at the Application Layer
056 *         (DPoP) (draft-ietf-oauth-dpop-03)
057 * </ul>
058 */
059@Immutable
060public class DPoPAccessToken extends AccessToken {
061        
062        
063        private static final long serialVersionUID = 7745184045632691024L;
064        
065        
066        /**
067         * Creates a new minimal DPoP access token with the specified value.
068         * The optional lifetime and scope are left undefined.
069         *
070         * @param value The access token value. Must not be {@code null} or
071         *              empty string.
072         */
073        public DPoPAccessToken(final String value) {
074        
075                this(value, 0L, null);
076        }
077        
078        
079        /**
080         * Creates a new DPoP access token with the specified value and
081         * optional lifetime and scope.
082         *
083         * @param value    The access token value. Must not be {@code null} or
084         *                 empty string.
085         * @param lifetime The lifetime in seconds, 0 if not specified.
086         * @param scope    The scope, {@code null} if not specified.
087         */
088        public DPoPAccessToken(final String value, final long lifetime, final Scope scope) {
089        
090                super(AccessTokenType.DPOP, value, lifetime, scope);
091        }
092        
093        
094        /**
095         * Returns the HTTP Authorization header value for this DPoP access
096         * token.
097         *
098         * <p>Example:
099         *
100         * <pre>
101         * Authorization: DPoP aeniniu3oogh2quoot7Aipie9IeGh3te
102         * </pre>
103         *
104         * @return The HTTP Authorization header.
105         */
106        @Override
107        public String toAuthorizationHeader(){
108        
109                return "DPoP " + getValue();
110        }
111        
112        
113        @Override
114        public boolean equals(final Object object) {
115        
116                return object instanceof DPoPAccessToken &&
117                       this.toString().equals(object.toString());
118        }
119
120
121        /**
122         * Parses a DPoP access token from a JSON object access token
123         * response.
124         *
125         * @param jsonObject The JSON object to parse. Must not be 
126         *                   {@code null}.
127         *
128         * @return The DPoP access token.
129         *
130         * @throws ParseException If the JSON object couldn't be parsed to a
131         *                        DPoP access token.
132         */
133        public static DPoPAccessToken parse(final JSONObject jsonObject)
134                throws ParseException {
135
136                AccessTokenUtils.parseAndEnsureType(jsonObject, AccessTokenType.DPOP);
137                String accessTokenValue = AccessTokenUtils.parseValue(jsonObject);
138                long lifetime = AccessTokenUtils.parseLifetime(jsonObject);
139                Scope scope = AccessTokenUtils.parseScope(jsonObject);
140                return new DPoPAccessToken(accessTokenValue, lifetime, scope);
141        }
142        
143        
144        /**
145         * Parses an HTTP Authorization header for a DPoP access token.
146         *
147         * @param header The HTTP Authorization header value to parse. May be
148         *               {@code null} if the header is missing, in which case
149         *               an exception will be thrown.
150         *
151         * @return The DPoP access token.
152         *
153         * @throws ParseException If the HTTP Authorization header value 
154         *                        couldn't be parsed to a DPoP access token.
155         */
156        public static DPoPAccessToken parse(final String header)
157                throws ParseException {
158                
159                return new DPoPAccessToken(AccessTokenUtils.parseValueFromHeader(header, AccessTokenType.DPOP));
160        }
161        
162        
163        /**
164         * Parses a query or form parameters map for a bearer access token.
165         *
166         * @param parameters The query parameters. Must not be {@code null}.
167         *
168         * @return The bearer access token.
169         *
170         * @throws ParseException If a bearer access token wasn't found in the
171         *                        parameters.
172         */
173        public static DPoPAccessToken parse(final Map<String,List<String>> parameters)
174                throws ParseException {
175                
176                return new DPoPAccessToken(AccessTokenUtils.parseValueFromQueryParameters(parameters, AccessTokenType.DPOP));
177        }
178        
179        
180        
181        /**
182         * Parses an HTTP request for a bearer access token.
183         * 
184         * @param request The HTTP request to parse. Must not be {@code null}.
185         * 
186         * @return The bearer access token.
187         * 
188         * @throws ParseException If a bearer access token wasn't found in the
189         *                        HTTP request.
190         */
191        public static DPoPAccessToken parse(final HTTPRequest request)
192                throws ParseException {
193
194                // See http://tools.ietf.org/html/rfc6750#section-2
195                String authzHeader = request.getAuthorization();
196
197                if (authzHeader != null) {
198                        return parse(authzHeader);
199                }
200
201                // Try alternative token locations, form and query string are
202                // parameters are not differentiated here
203                Map<String,List<String>> params = request.getQueryParameters();
204                return parse(params);
205        }
206}