001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2023, 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.client;
019
020import com.nimbusds.oauth2.sdk.util.URIUtils;
021
022import java.net.URI;
023import java.util.Arrays;
024import java.util.Collections;
025import java.util.HashSet;
026import java.util.Set;
027
028
029/**
030 * Redirection URI validator.
031 */
032public final class RedirectURIValidator {
033
034
035        /**
036         * Prohibited {@code redirect_uri} schemes. See
037         * https://security.lauritz-holtmann.de/post/sso-security-redirect-uri/.
038         */
039        public static final Set<String> PROHIBITED_REDIRECT_URI_SCHEMES =
040                Collections.unmodifiableSet(new HashSet<>(Arrays.asList("data", "javascript", "vbscript")));
041
042
043        /**
044         * Prohibited {@code redirect_uri} query parameters. See "OAuth 2.0
045         * Redirect URI Validation Falls Short, Literally", by Tommaso
046         * Innocenti, Matteo Golinelli, Kaan Onarlioglu, Bruno Crispo, Engin
047         * Kirda. Presented at OAuth Security Workshop 2023.
048         */
049        public static final Set<String> PROHIBITED_REDIRECT_URI_QUERY_PARAMETER_NAMES =
050                Collections.unmodifiableSet(new HashSet<>(Arrays.asList("code", "state", "response")));
051
052        /**
053         * Ensures the specified redirection URI is legal.
054         *
055         * <p>Checks:
056         *
057         * <ul>
058         *     <li>Must not contain fragment;
059         *     <li>Must not have a {@link #PROHIBITED_REDIRECT_URI_SCHEMES
060         *         prohibited URI scheme};
061         *     <li>Must not have a {@link #PROHIBITED_REDIRECT_URI_QUERY_PARAMETER_NAMES
062         *         prohibited query parameter}.
063         * </ul>
064         *
065         * @param redirectURI The redirect URI to check, {@code null} if not
066         *                    specified.
067         *
068         * @throws IllegalArgumentException If the redirection URI is illegal.
069         */
070        public static void ensureLegal(final URI redirectURI) {
071
072                if (redirectURI == null) {
073                        return;
074                }
075
076                if (redirectURI.getFragment() != null) {
077                        throw new IllegalArgumentException("The redirect_uri must not contain fragment");
078                }
079
080                URIUtils.ensureSchemeIsNotProhibited(redirectURI, ClientMetadata.PROHIBITED_REDIRECT_URI_SCHEMES);
081
082                URIUtils.ensureQueryIsNotProhibited(redirectURI, PROHIBITED_REDIRECT_URI_QUERY_PARAMETER_NAMES);
083        }
084
085
086        /**
087         * Prevents public instantiation.
088         */
089        private RedirectURIValidator() {}
090}