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 java.util.Collections;
022import java.util.LinkedHashMap;
023import java.util.List;
024import java.util.Map;
025
026import com.nimbusds.jose.util.Base64URL;
027import com.nimbusds.oauth2.sdk.util.MultivaluedMapUtils;
028import net.jcip.annotations.Immutable;
029
030
031/**
032 * SAML 2.0 bearer grant. Used in access token requests with a SAML 2.0 bearer
033 * assertion.
034 *
035 * <p>Related specifications:
036 *
037 * <ul>
038 *     <li>Assertion Framework for OAuth 2.0 Client Authentication and
039 *         Authorization Grants (RFC 7521), section 4.1.
040 *     <li>SAML 2.0 Profile for OAuth 2.0 Client Authentication and
041 *         Authorization Grants (RFC 7522), section-2.1.
042 * </ul>
043 */
044@Immutable
045public class SAML2BearerGrant extends AssertionGrant {
046
047
048        /**
049         * The grant type.
050         */
051        public static final GrantType GRANT_TYPE = GrantType.SAML2_BEARER;
052
053
054        /**
055         * Cached {@code unsupported_grant_type} exception.
056         */
057        private static final ParseException UNSUPPORTED_GRANT_TYPE_EXCEPTION
058                        = new ParseException("The \"grant_type\" must be " + GRANT_TYPE, OAuth2Error.UNSUPPORTED_GRANT_TYPE);
059
060
061        /**
062         * The SAML 2.0 assertion.
063         */
064        private final Base64URL assertion;
065
066
067        /**
068         * Creates a new SAML 2.0 bearer assertion grant.
069         *
070         * @param assertion The SAML 2.0 bearer assertion. Must not be
071         *                  {@code null}.
072         */
073        public SAML2BearerGrant(final Base64URL assertion) {
074
075                super(GRANT_TYPE);
076
077                if (assertion == null)
078                        throw new IllegalArgumentException("The SAML 2.0 bearer assertion must not be null");
079
080                this.assertion = assertion;
081        }
082
083
084        /**
085         * Gets the SAML 2.0 bearer assertion.
086         *
087         * @return The SAML 2.0 bearer assertion.
088         */
089        public Base64URL getSAML2Assertion() {
090
091                return assertion;
092        }
093
094
095        @Override
096        public String getAssertion() {
097
098                return assertion.toString();
099        }
100
101
102        @Override
103        public Map<String,List<String>> toParameters() {
104
105                Map<String,List<String>> params = new LinkedHashMap<>();
106                params.put("grant_type", Collections.singletonList(GRANT_TYPE.getValue()));
107                params.put("assertion", Collections.singletonList(assertion.toString()));
108                return params;
109        }
110
111
112        @Override
113        public boolean equals(Object o) {
114                if (this == o) return true;
115                if (o == null || getClass() != o.getClass()) return false;
116
117                SAML2BearerGrant that = (SAML2BearerGrant) o;
118
119                return assertion.equals(that.assertion);
120
121        }
122
123
124        @Override
125        public int hashCode() {
126                return assertion.hashCode();
127        }
128
129
130        /**
131         * Parses a SAML 2.0 bearer grant from the specified request body
132         * parameters.
133         *
134         * <p>Example:
135         *
136         * <pre>
137         * grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Asaml2-
138         * bearer&amp;assertion=PEFzc2VydGlvbiBJc3N1ZUluc3RhbnQ9IjIwMTEtMDU
139         * [...omitted for brevity...]aG5TdGF0ZW1lbnQ-PC9Bc3NlcnRpb24-
140         * </pre>
141         *
142         * @param params The parameters.
143         *
144         * @return The SAML 2.0 bearer grant.
145         *
146         * @throws ParseException If parsing failed.
147         */
148        public static SAML2BearerGrant parse(final Map<String,List<String>> params)
149                throws ParseException {
150
151                // Parse grant type
152                String grantTypeString = MultivaluedMapUtils.getFirstValue(params, "grant_type");
153
154                if (grantTypeString == null)
155                        throw MISSING_GRANT_TYPE_PARAM_EXCEPTION;
156
157                if (! GrantType.parse(grantTypeString).equals(GRANT_TYPE))
158                        throw UNSUPPORTED_GRANT_TYPE_EXCEPTION;
159
160                // Parse JWT assertion
161                String assertionString = MultivaluedMapUtils.getFirstValue(params, "assertion");
162
163                if (assertionString == null || assertionString.trim().isEmpty())
164                        throw MISSING_ASSERTION_PARAM_EXCEPTION;
165
166                return new SAML2BearerGrant(new Base64URL(assertionString));
167        }
168}