001package com.nimbusds.oauth2.sdk;
002
003
004import java.net.URI;
005import java.net.URISyntaxException;
006import java.util.LinkedHashMap;
007import java.util.Map;
008
009import net.jcip.annotations.Immutable;
010
011
012/**
013 * Authorisation code grant. Used in access token requests with an
014 * authorisation code.
015 *
016 * <p>Related specifications:
017 *
018 * <ul>
019 *     <li>OAuth 2.0 (RFC 6749), section 4.1.3.
020 * </ul>
021 */
022@Immutable
023public class AuthorizationCodeGrant extends AuthorizationGrant {
024
025
026        /**
027         * The grant type.
028         */
029        public static final GrantType GRANT_TYPE = GrantType.AUTHORIZATION_CODE;
030
031
032        /**
033         * The authorisation code received from the authorisation server.
034         */
035        private final AuthorizationCode code;
036
037
038        /**
039         * The conditionally required redirection URI in the initial
040         * authorisation request.
041         */
042        private final URI redirectURI;
043
044
045        /**
046         * Creates a new authorisation code grant.
047         *
048         * @param code        The authorisation code. Must not be {@code null}.
049         * @param redirectURI The redirection URI of the original authorisation
050         *                    request. Required if the {redirect_uri}
051         *                    parameter was included in the authorisation
052         *                    request, else {@code null}.
053         */
054        public AuthorizationCodeGrant(final AuthorizationCode code,
055                                      final URI redirectURI) {
056
057                super(GRANT_TYPE);
058
059                if (code == null)
060                        throw new IllegalArgumentException("The authorisation code must not be null");
061
062                this.code = code;
063
064                this.redirectURI = redirectURI;
065        }
066
067
068        /**
069         * Gets the authorisation code.
070         *
071         * @return The authorisation code.
072         */
073        public AuthorizationCode getAuthorizationCode() {
074
075                return code;
076        }
077
078
079        /**
080         * Gets the redirection URI of the original authorisation request.
081         *
082         * @return The redirection URI, {@code null} if the
083         *         {@code redirect_uri} parameter was not included in the
084         *         original authorisation request.
085         */
086        public URI getRedirectionURI() {
087
088                return redirectURI;
089        }
090
091
092        @Override
093        public Map<String,String> toParameters() {
094
095                Map<String,String> params = new LinkedHashMap<>();
096                params.put("grant_type", GRANT_TYPE.getValue());
097                params.put("code", code.getValue());
098
099                if (redirectURI != null)
100                        params.put("redirect_uri", redirectURI.toString());
101
102                return params;
103        }
104
105
106        /**
107         * Parses an authorisation code grant from the specified parameters.
108         *
109         * <p>Example:
110         *
111         * <pre>
112         * grant_type=authorization_code
113         * code=SplxlOBeZQQYbYS6WxSbIA
114         * redirect_uri=https://Fclient.example.com/cb
115         * </pre>
116         *
117         * @param params The parameters.
118         *
119         * @return The authorisation code grant.
120         *
121         * @throws ParseException If parsing failed.
122         */
123        public static AuthorizationCodeGrant parse(final Map<String,String> params)
124                throws ParseException {
125
126                // Parse grant type
127                String grantTypeString = params.get("grant_type");
128
129                if (grantTypeString == null)
130                        throw new ParseException("Missing \"grant_type\" parameter", OAuth2Error.INVALID_REQUEST);
131
132                if (! GrantType.parse(grantTypeString).equals(GRANT_TYPE))
133                        throw new ParseException("The \"grant_type\" must be " + GRANT_TYPE, OAuth2Error.UNSUPPORTED_GRANT_TYPE);
134
135                // Parse authorisation code
136                String codeString = params.get("code");
137
138                if (codeString == null || codeString.trim().isEmpty())
139                        throw new ParseException("Missing or empty \"code\" parameter", OAuth2Error.INVALID_REQUEST);
140
141                AuthorizationCode code = new AuthorizationCode(codeString);
142
143                // Parse optional redirection URI
144                String redirectURIString = params.get("redirect_uri");
145
146                URI redirectURI = null;
147
148                if (redirectURIString != null) {
149
150                        try {
151                                redirectURI = new URI(redirectURIString);
152                        } catch (URISyntaxException e) {
153                                throw new ParseException("Invalid \"redirect_uri\" parameter: " + e.getMessage(), OAuth2Error.INVALID_REQUEST, e);
154                        }
155                }
156
157                return new AuthorizationCodeGrant(code, redirectURI);
158        }
159}