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        /**
054         * Ensures the specified redirection URI is legal.
055         *
056         * <p>The URI:
057         *
058         * <ul>
059         *     <li>Must not contain fragment;
060         *     <li>Must not have a {@link #PROHIBITED_REDIRECT_URI_SCHEMES
061         *         prohibited URI scheme};
062         *     <li>Must not have a {@link #PROHIBITED_REDIRECT_URI_QUERY_PARAMETER_NAMES
063         *         prohibited query parameter}.
064         * </ul>
065         *
066         * @param redirectURI The redirect URI to check, {@code null} if not
067         *                    specified.
068         *
069         * @throws IllegalArgumentException If the redirection URI is illegal.
070         */
071        public static void ensureLegal(final URI redirectURI) {
072
073                if (redirectURI == null) {
074                        return;
075                }
076
077                if (redirectURI.getFragment() != null) {
078                        throw new IllegalArgumentException("The redirect_uri must not contain fragment");
079                }
080
081                URIUtils.ensureSchemeIsNotProhibited(redirectURI, ClientMetadata.PROHIBITED_REDIRECT_URI_SCHEMES);
082
083                URIUtils.ensureQueryIsNotProhibited(redirectURI, PROHIBITED_REDIRECT_URI_QUERY_PARAMETER_NAMES);
084        }
085
086
087        /**
088         * Prevents public instantiation.
089         */
090        private RedirectURIValidator() {}
091}