001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.shiro.web.filter.authz;
020
021import org.apache.shiro.lang.util.StringUtils;
022
023import javax.servlet.ServletRequest;
024import javax.servlet.ServletResponse;
025import java.util.regex.Pattern;
026import java.util.Map;
027
028/**
029 * A Filter that can allow or deny access based on the host that sent the request.
030 *
031 * <b>WARNING:</b> NOT YET FULLY IMPLEMENTED!!!  Work in progress.
032 *
033 * @since 1.0
034 */
035@SuppressWarnings("checkstyle:JavadocVariable")
036public class HostFilter extends AuthorizationFilter {
037
038    /**
039     * IPV4 quad regex.
040     */
041    public static final String IPV4_QUAD_REGEX = "(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2(?:[0-4][0-9]|5[0-5]))";
042
043    /**
044     * IPV4 regex.
045     */
046    public static final String IPV4_REGEX = "(?:" + IPV4_QUAD_REGEX + "\\.){3}" + IPV4_QUAD_REGEX + "$";
047
048    /**
049     * IPV4 pattern.
050     */
051    public static final Pattern IPV4_PATTERN = Pattern.compile(IPV4_REGEX);
052
053    public static final String PRIVATE_CLASS_B_SUBSET = "(?:1[6-9]|2[0-9]|3[0-1])";
054
055    public static final String PRIVATE_CLASS_A_REGEX = "10\\.(?:" + IPV4_QUAD_REGEX + "\\.){2}" + IPV4_QUAD_REGEX + "$";
056
057    public static final String PRIVATE_CLASS_B_REGEX =
058            "172\\." + PRIVATE_CLASS_B_SUBSET + "\\." + IPV4_QUAD_REGEX + "\\." + IPV4_QUAD_REGEX + "$";
059
060    public static final String PRIVATE_CLASS_C_REGEX = "192\\.168\\." + IPV4_QUAD_REGEX + "\\." + IPV4_QUAD_REGEX + "$";
061
062    //user-configured IP (which can be wildcarded) to constructed regex mapping
063    Map<String, String> authorizedIps;
064    Map<String, String> deniedIps;
065    Map<String, String> authorizedHostnames;
066    Map<String, String> deniedHostnames;
067
068
069    public void setAuthorizedHosts(String authorizedHosts) {
070        if (!StringUtils.hasText(authorizedHosts)) {
071            throw new IllegalArgumentException("authorizedHosts argument cannot be null or empty.");
072        }
073        String[] hosts = StringUtils.tokenizeToStringArray(authorizedHosts, ", \t");
074
075        for (String host : hosts) {
076            //replace any periods with \\. to ensure the regex works:
077            String periodsReplaced = host.replace(".", "\\.");
078            //check for IPv4:
079            String wildcardsReplaced = periodsReplaced.replace("*", IPV4_QUAD_REGEX);
080
081            if (IPV4_PATTERN.matcher(wildcardsReplaced).matches()) {
082                authorizedIps.put(host, wildcardsReplaced);
083            }
084        }
085
086    }
087
088    public void setDeniedHosts(String deniedHosts) {
089        if (!StringUtils.hasText(deniedHosts)) {
090            throw new IllegalArgumentException("deniedHosts argument cannot be null or empty.");
091        }
092    }
093
094    protected boolean isIpv4Candidate(String host) {
095        String[] quads = StringUtils.tokenizeToStringArray(host, ".");
096        if (quads == null || quads.length != 4) {
097            return false;
098        }
099        for (String quad : quads) {
100            if (!quad.equals("*")) {
101                try {
102                    Integer.parseInt(quad);
103                } catch (NumberFormatException nfe) {
104                    return false;
105                }
106            }
107        }
108        return true;
109    }
110
111    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
112        throw new UnsupportedOperationException("Not yet fully implemented!!!");
113    }
114}