11/*
2- * Copyright (c) 1999, 2002 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 1999, 2022 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
2828import javax .naming .*;
2929import java .net .MalformedURLException ;
3030import java .io .UnsupportedEncodingException ;
31+ import java .net .URI ;
32+ import java .security .AccessController ;
33+ import java .security .PrivilegedAction ;
34+ import java .util .Locale ;
3135import java .util .StringTokenizer ;
3236import com .sun .jndi .toolkit .url .Uri ;
3337import com .sun .jndi .toolkit .url .UrlUtil ;
6468
6569public final class LdapURL extends Uri {
6670
71+ private static final String PARSE_MODE_PROP = "com.sun.jndi.ldapURLParsing" ;
72+ private static final ParseMode DEFAULT_PARSE_MODE = ParseMode .COMPAT ;
73+
74+ public static final ParseMode PARSE_MODE ;
75+ static {
76+ PrivilegedAction <String > action = () ->
77+ System .getProperty (PARSE_MODE_PROP , DEFAULT_PARSE_MODE .toString ());
78+ ParseMode parseMode = DEFAULT_PARSE_MODE ;
79+ try {
80+ @ SuppressWarnings ("removal" )
81+ String mode = AccessController .doPrivileged (action );
82+ parseMode = ParseMode .valueOf (mode .toUpperCase (Locale .ROOT ));
83+ } catch (Throwable t ) {
84+ parseMode = DEFAULT_PARSE_MODE ;
85+ } finally {
86+ PARSE_MODE = parseMode ;
87+ }
88+ }
89+
6790 private boolean useSsl = false ;
6891 private String DN = null ;
6992 private String attributes = null ;
@@ -83,7 +106,7 @@ public LdapURL(String url) throws NamingException {
83106 useSsl = scheme .equalsIgnoreCase ("ldaps" );
84107
85108 if (! (scheme .equalsIgnoreCase ("ldap" ) || useSsl )) {
86- throw new MalformedURLException ( "Not an LDAP URL: " + url );
109+ throw newInvalidURISchemeException ( url );
87110 }
88111
89112 parsePathAndQuery (); // DN, attributes, scope, filter, extensions
@@ -99,6 +122,21 @@ public LdapURL(String url) throws NamingException {
99122 }
100123 }
101124
125+ @ Override
126+ protected MalformedURLException newInvalidURISchemeException (String uri ) {
127+ return new MalformedURLException ("Not an LDAP URL: " + uri );
128+ }
129+
130+ @ Override
131+ protected boolean isSchemeOnly (String uri ) {
132+ return isLdapSchemeOnly (uri );
133+ }
134+
135+ @ Override
136+ protected ParseMode parseMode () {
137+ return PARSE_MODE ;
138+ }
139+
102140 /**
103141 * Returns true if the URL is an LDAPS URL.
104142 */
@@ -151,13 +189,33 @@ public static String[] fromList(String urlList) throws NamingException {
151189 StringTokenizer st = new StringTokenizer (urlList , " " );
152190
153191 while (st .hasMoreTokens ()) {
154- urls [i ++] = st .nextToken ();
192+ // we don't accept scheme-only URLs here
193+ urls [i ++] = validateURI (st .nextToken ());
155194 }
156195 String [] trimmed = new String [i ];
157196 System .arraycopy (urls , 0 , trimmed , 0 , i );
158197 return trimmed ;
159198 }
160199
200+ public static boolean isLdapSchemeOnly (String uri ) {
201+ return "ldap:" .equals (uri ) || "ldaps:" .equals (uri );
202+ }
203+
204+ public static String validateURI (String uri ) {
205+ // no validation in legacy mode parsing
206+ if (PARSE_MODE == ParseMode .LEGACY ) {
207+ return uri ;
208+ }
209+
210+ // special case of scheme-only URIs
211+ if (isLdapSchemeOnly (uri )) {
212+ return uri ;
213+ }
214+
215+ // use java.net.URI to validate the uri syntax
216+ return URI .create (uri ).toString ();
217+ }
218+
161219 /**
162220 * Determines whether an LDAP URL has query components.
163221 */
@@ -181,7 +239,8 @@ static String toUrlString(String host, int port, String dn, boolean useSsl)
181239 String p = (port != -1 ) ? (":" + port ) : "" ;
182240 String d = (dn != null ) ? ("/" + UrlUtil .encode (dn , "UTF8" )) : "" ;
183241
184- return useSsl ? "ldaps://" + h + p + d : "ldap://" + h + p + d ;
242+ String uri = useSsl ? "ldaps://" + h + p + d : "ldap://" + h + p + d ;
243+ return validateURI (uri );
185244 } catch (UnsupportedEncodingException e ) {
186245 // UTF8 should always be supported
187246 throw new IllegalStateException ("UTF-8 encoding unavailable" );
0 commit comments