blob: 52b3ef4d8f729a1d5f0e9a7e804615d80ffa36b2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.bval.extras.constraints.net;
import static java.util.Arrays.asList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* <p><b>Domain name</b> validation routines.</p>
*
* <p>
* This validator provides methods for validating Internet domain names
* and top-level domains.
* </p>
*
* <p>Domain names are evaluated according
* to the standards <a href="http://www.ietf.org/rfc/rfc1034.txt">RFC1034</a>,
* section 3, and <a href="http://www.ietf.org/rfc/rfc1123.txt">RFC1123</a>,
* section 2.1. No accomodation is provided for the specialized needs of
* other applications; if the domain name has been URL-encoded, for example,
* validation will fail even though the equivalent plaintext version of the
* same name would have passed.
* </p>
*
* <p>
* Validation is also provided for top-level domains (TLDs) as defined and
* maintained by the Internet Assigned Numbers Authority (IANA):
* </p>
*
* <ul>
* <li>{@link #isValidInfrastructureTld} - validates infrastructure TLDs
* (<code>.arpa</code>, etc.)</li>
* <li>{@link #isValidGenericTld} - validates generic TLDs
* (<code>.com, .org</code>, etc.)</li>
* <li>{@link #isValidCountryCodeTld} - validates country code TLDs
* (<code>.us, .uk, .cn</code>, etc.)</li>
* </ul>
*
* <p>
* (<b>NOTE</b>: This class does not provide IP address lookup for domain names or
* methods to ensure that a given domain name matches a specific IP; see
* {@link java.net.InetAddress} for that functionality.)
* </p>
*/
public class DomainValidator implements ConstraintValidator<Domain, String> {
private boolean allowLocal;
// Regular expression strings for hostnames (derived from RFC2396 and RFC 1123)
private static final Pattern DOMAIN_LABEL = Pattern.compile("\\p{Alnum}(?>[\\p{Alnum}-]*\\p{Alnum})*");
private static final Pattern DOMAIN_NAME_REGEX = Pattern.compile("^(?:"
+ DOMAIN_LABEL.pattern()
+ "\\.)+(\\p{Alpha}{2,})$");
/**
* {@inheritDoc}
*/
public boolean isValid(String domain, ConstraintValidatorContext context) {
Matcher matcher = DOMAIN_NAME_REGEX.matcher(domain);
if (matcher.matches()) {
domain = matcher.group(1);
return isValidTld(domain);
} else if (allowLocal && DOMAIN_LABEL.matcher(domain).matches()) {
return true;
}
return false;
}
/**
* Returns true if the specified <code>String</code> matches any
* IANA-defined top-level domain. Leading dots are ignored if present.
* The search is case-sensitive.
*
* @param tld the parameter to check for TLD status
* @return true if the parameter is a TLD
*/
boolean isValidTld(String tld) {
if (allowLocal && isValidLocalTld(tld)) {
return true;
}
tld = chompLeadingDot(tld).toLowerCase();
return isValidInfrastructureTld(tld)
|| isValidGenericTld(tld)
|| isValidCountryCodeTld(tld);
}
/**
* Returns true if the specified <code>String</code> matches any
* IANA-defined infrastructure top-level domain. Leading dots are
* ignored if present. The search is case-sensitive.
*
* @param iTld the parameter to check for infrastructure TLD status
* @return true if the parameter is an infrastructure TLD
*/
static boolean isValidInfrastructureTld(String iTld) {
return INFRASTRUCTURE_TLDS.contains(iTld);
}
/**
* Returns true if the specified <code>String</code> matches any
* IANA-defined generic top-level domain. Leading dots are ignored
* if present. The search is case-sensitive.
*
* @param gTld the parameter to check for generic TLD status
* @return true if the parameter is a generic TLD
*/
static boolean isValidGenericTld(String gTld) {
return GENERIC_TLDS.contains(gTld);
}
/**
* Returns true if the specified <code>String</code> matches any
* IANA-defined country code top-level domain. Leading dots are
* ignored if present. The search is case-sensitive.
*
* @param ccTld the parameter to check for country code TLD status
* @return true if the parameter is a country code TLD
*/
static boolean isValidCountryCodeTld(String ccTld) {
return COUNTRY_CODE_TLDS.contains(ccTld);
}
/**
* Returns true if the specified <code>String</code> matches any
* widely used "local" domains (localhost or localdomain). Leading dots are
* ignored if present. The search is case-sensitive.
*
* @param iTld the parameter to check for local TLD status
* @return true if the parameter is an local TLD
*/
static boolean isValidLocalTld(String iTld) {
return LOCAL_TLDS.contains(iTld);
}
private static String chompLeadingDot(String str) {
if (str.startsWith(".")) {
return str.substring(1);
}
return str;
}
// ---------------------------------------------
// ----- TLDs defined by IANA
// ----- Authoritative and comprehensive list at:
// ----- http://data.iana.org/TLD/tlds-alpha-by-domain.txt
private static final List<String> INFRASTRUCTURE_TLDS = asList(
"arpa", // internet infrastructure
"root" // diagnostic marker for non-truncated root zone
);
private static final List<String> GENERIC_TLDS = asList(
"aero", // air transport industry
"asia", // Pan-Asia/Asia Pacific
"biz", // businesses
"cat", // Catalan linguistic/cultural community
"com", // commercial enterprises
"coop", // cooperative associations
"info", // informational sites
"jobs", // Human Resource managers
"mobi", // mobile products and services
"museum", // museums, surprisingly enough
"name", // individuals' sites
"net", // internet support infrastructure/business
"org", // noncommercial organizations
"pro", // credentialed professionals and entities
"tel", // contact data for businesses and individuals
"travel", // entities in the travel industry
"gov", // United States Government
"edu", // accredited postsecondary US education entities
"mil", // United States Military
"int" // organizations established by international treaty
);
private static final List<String> COUNTRY_CODE_TLDS = asList(
"ac", // Ascension Island
"ad", // Andorra
"ae", // United Arab Emirates
"af", // Afghanistan
"ag", // Antigua and Barbuda
"ai", // Anguilla
"al", // Albania
"am", // Armenia
"an", // Netherlands Antilles
"ao", // Angola
"aq", // Antarctica
"ar", // Argentina
"as", // American Samoa
"at", // Austria
"au", // Australia (includes Ashmore and Cartier Islands and Coral Sea Islands)
"aw", // Aruba
"ax", // Åland
"az", // Azerbaijan
"ba", // Bosnia and Herzegovina
"bb", // Barbados
"bd", // Bangladesh
"be", // Belgium
"bf", // Burkina Faso
"bg", // Bulgaria
"bh", // Bahrain
"bi", // Burundi
"bj", // Benin
"bm", // Bermuda
"bn", // Brunei Darussalam
"bo", // Bolivia
"br", // Brazil
"bs", // Bahamas
"bt", // Bhutan
"bv", // Bouvet Island
"bw", // Botswana
"by", // Belarus
"bz", // Belize
"ca", // Canada
"cc", // Cocos (Keeling) Islands
"cd", // Democratic Republic of the Congo (formerly Zaire)
"cf", // Central African Republic
"cg", // Republic of the Congo
"ch", // Switzerland
"ci", // Côte d'Ivoire
"ck", // Cook Islands
"cl", // Chile
"cm", // Cameroon
"cn", // China, mainland
"co", // Colombia
"cr", // Costa Rica
"cu", // Cuba
"cv", // Cape Verde
"cx", // Christmas Island
"cy", // Cyprus
"cz", // Czech Republic
"de", // Germany
"dj", // Djibouti
"dk", // Denmark
"dm", // Dominica
"do", // Dominican Republic
"dz", // Algeria
"ec", // Ecuador
"ee", // Estonia
"eg", // Egypt
"er", // Eritrea
"es", // Spain
"et", // Ethiopia
"eu", // European Union
"fi", // Finland
"fj", // Fiji
"fk", // Falkland Islands
"fm", // Federated States of Micronesia
"fo", // Faroe Islands
"fr", // France
"ga", // Gabon
"gb", // Great Britain (United Kingdom)
"gd", // Grenada
"ge", // Georgia
"gf", // French Guiana
"gg", // Guernsey
"gh", // Ghana
"gi", // Gibraltar
"gl", // Greenland
"gm", // The Gambia
"gn", // Guinea
"gp", // Guadeloupe
"gq", // Equatorial Guinea
"gr", // Greece
"gs", // South Georgia and the South Sandwich Islands
"gt", // Guatemala
"gu", // Guam
"gw", // Guinea-Bissau
"gy", // Guyana
"hk", // Hong Kong
"hm", // Heard Island and McDonald Islands
"hn", // Honduras
"hr", // Croatia (Hrvatska)
"ht", // Haiti
"hu", // Hungary
"id", // Indonesia
"ie", // Ireland (Éire)
"il", // Israel
"im", // Isle of Man
"in", // India
"io", // British Indian Ocean Territory
"iq", // Iraq
"ir", // Iran
"is", // Iceland
"it", // Italy
"je", // Jersey
"jm", // Jamaica
"jo", // Jordan
"jp", // Japan
"ke", // Kenya
"kg", // Kyrgyzstan
"kh", // Cambodia (Khmer)
"ki", // Kiribati
"km", // Comoros
"kn", // Saint Kitts and Nevis
"kp", // North Korea
"kr", // South Korea
"kw", // Kuwait
"ky", // Cayman Islands
"kz", // Kazakhstan
"la", // Laos (currently being marketed as the official domain for Los Angeles)
"lb", // Lebanon
"lc", // Saint Lucia
"li", // Liechtenstein
"lk", // Sri Lanka
"lr", // Liberia
"ls", // Lesotho
"lt", // Lithuania
"lu", // Luxembourg
"lv", // Latvia
"ly", // Libya
"ma", // Morocco
"mc", // Monaco
"md", // Moldova
"me", // Montenegro
"mg", // Madagascar
"mh", // Marshall Islands
"mk", // Republic of Macedonia
"ml", // Mali
"mm", // Myanmar
"mn", // Mongolia
"mo", // Macau
"mp", // Northern Mariana Islands
"mq", // Martinique
"mr", // Mauritania
"ms", // Montserrat
"mt", // Malta
"mu", // Mauritius
"mv", // Maldives
"mw", // Malawi
"mx", // Mexico
"my", // Malaysia
"mz", // Mozambique
"na", // Namibia
"nc", // New Caledonia
"ne", // Niger
"nf", // Norfolk Island
"ng", // Nigeria
"ni", // Nicaragua
"nl", // Netherlands
"no", // Norway
"np", // Nepal
"nr", // Nauru
"nu", // Niue
"nz", // New Zealand
"om", // Oman
"pa", // Panama
"pe", // Peru
"pf", // French Polynesia With Clipperton Island
"pg", // Papua New Guinea
"ph", // Philippines
"pk", // Pakistan
"pl", // Poland
"pm", // Saint-Pierre and Miquelon
"pn", // Pitcairn Islands
"pr", // Puerto Rico
"ps", // Palestinian territories (PA-controlled West Bank and Gaza Strip)
"pt", // Portugal
"pw", // Palau
"py", // Paraguay
"qa", // Qatar
"re", // Réunion
"ro", // Romania
"rs", // Serbia
"ru", // Russia
"rw", // Rwanda
"sa", // Saudi Arabia
"sb", // Solomon Islands
"sc", // Seychelles
"sd", // Sudan
"se", // Sweden
"sg", // Singapore
"sh", // Saint Helena
"si", // Slovenia
"sj", // Svalbard and Jan Mayen Islands Not in use (Norwegian dependencies; see .no)
"sk", // Slovakia
"sl", // Sierra Leone
"sm", // San Marino
"sn", // Senegal
"so", // Somalia
"sr", // Suriname
"st", // São Tomé and Príncipe
"su", // Soviet Union (deprecated)
"sv", // El Salvador
"sy", // Syria
"sz", // Swaziland
"tc", // Turks and Caicos Islands
"td", // Chad
"tf", // French Southern and Antarctic Lands
"tg", // Togo
"th", // Thailand
"tj", // Tajikistan
"tk", // Tokelau
"tl", // East Timor (deprecated old code)
"tm", // Turkmenistan
"tn", // Tunisia
"to", // Tonga
"tp", // East Timor
"tr", // Turkey
"tt", // Trinidad and Tobago
"tv", // Tuvalu
"tw", // Taiwan, Republic of China
"tz", // Tanzania
"ua", // Ukraine
"ug", // Uganda
"uk", // United Kingdom
"um", // United States Minor Outlying Islands
"us", // United States of America
"uy", // Uruguay
"uz", // Uzbekistan
"va", // Vatican City State
"vc", // Saint Vincent and the Grenadines
"ve", // Venezuela
"vg", // British Virgin Islands
"vi", // U.S. Virgin Islands
"vn", // Vietnam
"vu", // Vanuatu
"wf", // Wallis and Futuna
"ws", // Samoa (formerly Western Samoa)
"ye", // Yemen
"yt", // Mayotte
"yu", // Serbia and Montenegro (originally Yugoslavia)
"za", // South Africa
"zm", // Zambia
"zw" // Zimbabwe
);
private static final List<String> LOCAL_TLDS = asList(
"localhost", // RFC2606 defined
"localdomain" // Also widely used as localhost.localdomain
);
/**
* {@inheritDoc}
*/
public void initialize(Domain domain) {
allowLocal = domain.allowLocal();
}
}