Search in sources :

Example 1 with NettyHttpSecurityConfiguration

use of org.apache.camel.component.netty4.http.NettyHttpSecurityConfiguration in project camel by apache.

the class NettyHttpComponent method createEndpoint.

@Override
protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
    NettyConfiguration config;
    if (getConfiguration() != null) {
        config = getConfiguration().copy();
    } else {
        config = new NettyHttpConfiguration();
    }
    HeaderFilterStrategy headerFilterStrategy = resolveAndRemoveReferenceParameter(parameters, "headerFilterStrategy", HeaderFilterStrategy.class);
    // merge any custom bootstrap configuration on the config
    NettyServerBootstrapConfiguration bootstrapConfiguration = resolveAndRemoveReferenceParameter(parameters, "bootstrapConfiguration", NettyServerBootstrapConfiguration.class);
    if (bootstrapConfiguration != null) {
        Map<String, Object> options = new HashMap<String, Object>();
        if (IntrospectionSupport.getProperties(bootstrapConfiguration, options, null, false)) {
            IntrospectionSupport.setProperties(getCamelContext().getTypeConverter(), config, options);
        }
    }
    // any custom security configuration
    NettyHttpSecurityConfiguration securityConfiguration = resolveAndRemoveReferenceParameter(parameters, "securityConfiguration", NettyHttpSecurityConfiguration.class);
    Map<String, Object> securityOptions = IntrospectionSupport.extractProperties(parameters, "securityConfiguration.");
    NettyHttpBinding bindingFromUri = resolveAndRemoveReferenceParameter(parameters, "nettyHttpBinding", NettyHttpBinding.class);
    // are we using a shared http server?
    int sharedPort = -1;
    NettySharedHttpServer shared = resolveAndRemoveReferenceParameter(parameters, "nettySharedHttpServer", NettySharedHttpServer.class);
    if (shared != null) {
        // use port number from the shared http server
        LOG.debug("Using NettySharedHttpServer: {} with port: {}", shared, shared.getPort());
        sharedPort = shared.getPort();
    }
    // we must include the protocol in the remaining
    boolean hasProtocol = remaining.startsWith("http://") || remaining.startsWith("http:") || remaining.startsWith("https://") || remaining.startsWith("https:");
    if (!hasProtocol) {
        // http is the default protocol
        remaining = "http://" + remaining;
    }
    boolean hasSlash = remaining.startsWith("http://") || remaining.startsWith("https://");
    if (!hasSlash) {
        // must have double slash after protocol
        if (remaining.startsWith("http:")) {
            remaining = "http://" + remaining.substring(5);
        } else {
            remaining = "https://" + remaining.substring(6);
        }
    }
    LOG.debug("Netty http url: {}", remaining);
    // set port on configuration which is either shared or using default values
    if (sharedPort != -1) {
        config.setPort(sharedPort);
    } else if (config.getPort() == -1 || config.getPort() == 0) {
        if (remaining.startsWith("http:")) {
            config.setPort(80);
        } else if (remaining.startsWith("https:")) {
            config.setPort(443);
        }
    }
    if (config.getPort() == -1) {
        throw new IllegalArgumentException("Port number must be configured");
    }
    // configure configuration
    config = parseConfiguration(config, remaining, parameters);
    setProperties(config, parameters);
    // validate config
    config.validateConfiguration();
    // create the address uri which includes the remainder parameters (which
    // is not configuration parameters for this component)
    URI u = new URI(UnsafeUriCharactersEncoder.encodeHttpURI(remaining));
    String addressUri = URISupport.createRemainingURI(u, parameters).toString();
    NettyHttpEndpoint answer = new NettyHttpEndpoint(addressUri, this, config);
    // instance that can cause side-effects
    if (answer.getNettyHttpBinding() == null) {
        Object binding = null;
        if (bindingFromUri != null) {
            binding = bindingFromUri;
        } else {
            binding = getNettyHttpBinding();
        }
        if (binding instanceof RestNettyHttpBinding) {
            NettyHttpBinding copy = ((RestNettyHttpBinding) binding).copy();
            answer.setNettyHttpBinding(copy);
        } else if (binding instanceof DefaultNettyHttpBinding) {
            NettyHttpBinding copy = ((DefaultNettyHttpBinding) binding).copy();
            answer.setNettyHttpBinding(copy);
        }
    }
    if (headerFilterStrategy != null) {
        answer.setHeaderFilterStrategy(headerFilterStrategy);
    } else if (answer.getHeaderFilterStrategy() == null) {
        answer.setHeaderFilterStrategy(getHeaderFilterStrategy());
    }
    if (securityConfiguration != null) {
        answer.setSecurityConfiguration(securityConfiguration);
    } else if (answer.getSecurityConfiguration() == null) {
        answer.setSecurityConfiguration(getSecurityConfiguration());
    }
    // configure any security options
    if (securityOptions != null && !securityOptions.isEmpty()) {
        securityConfiguration = answer.getSecurityConfiguration();
        if (securityConfiguration == null) {
            securityConfiguration = new NettyHttpSecurityConfiguration();
            answer.setSecurityConfiguration(securityConfiguration);
        }
        setProperties(securityConfiguration, securityOptions);
        validateParameters(uri, securityOptions, null);
    }
    answer.setNettySharedHttpServer(shared);
    return answer;
}
Also used : HashMap(java.util.HashMap) HeaderFilterStrategy(org.apache.camel.spi.HeaderFilterStrategy) NettyServerBootstrapConfiguration(org.apache.camel.component.netty4.NettyServerBootstrapConfiguration) URI(java.net.URI) Endpoint(org.apache.camel.Endpoint) NettyConfiguration(org.apache.camel.component.netty4.NettyConfiguration)

Example 2 with NettyHttpSecurityConfiguration

use of org.apache.camel.component.netty4.http.NettyHttpSecurityConfiguration in project camel by apache.

the class HttpServerChannelHandler method channelRead0.

@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
    HttpRequest request = (HttpRequest) msg;
    LOG.debug("Message received: {}", request);
    if (consumer.isSuspended()) {
        // are we suspended?
        LOG.debug("Consumer suspended, cannot service request {}", request);
        HttpResponse response = new DefaultHttpResponse(HTTP_1_1, SERVICE_UNAVAILABLE);
        response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
        response.headers().set(Exchange.CONTENT_LENGTH, 0);
        ctx.writeAndFlush(response);
        ctx.channel().close();
        return;
    }
    // if its an OPTIONS request then return which methods is allowed
    boolean isRestrictedToOptions = consumer.getEndpoint().getHttpMethodRestrict() != null && consumer.getEndpoint().getHttpMethodRestrict().contains("OPTIONS");
    if ("OPTIONS".equals(request.method().name()) && !isRestrictedToOptions) {
        String s;
        if (consumer.getEndpoint().getHttpMethodRestrict() != null) {
            s = "OPTIONS," + consumer.getEndpoint().getHttpMethodRestrict();
        } else {
            // allow them all
            s = "GET,HEAD,POST,PUT,DELETE,TRACE,OPTIONS,CONNECT,PATCH";
        }
        HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
        response.headers().set("Allow", s);
        response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
        response.headers().set(Exchange.CONTENT_LENGTH, 0);
        ctx.writeAndFlush(response);
        return;
    }
    if (consumer.getEndpoint().getHttpMethodRestrict() != null && !consumer.getEndpoint().getHttpMethodRestrict().contains(request.method().name())) {
        HttpResponse response = new DefaultHttpResponse(HTTP_1_1, METHOD_NOT_ALLOWED);
        response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
        response.headers().set(Exchange.CONTENT_LENGTH, 0);
        ctx.writeAndFlush(response);
        ctx.channel().close();
        return;
    }
    if ("TRACE".equals(request.method().name()) && !consumer.getEndpoint().isTraceEnabled()) {
        HttpResponse response = new DefaultHttpResponse(HTTP_1_1, METHOD_NOT_ALLOWED);
        response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
        response.headers().set(Exchange.CONTENT_LENGTH, 0);
        ctx.writeAndFlush(response);
        ctx.channel().close();
        return;
    }
    // must include HOST header as required by HTTP 1.1
    if (!request.headers().contains(HttpHeaderNames.HOST.toString())) {
        HttpResponse response = new DefaultHttpResponse(HTTP_1_1, BAD_REQUEST);
        //response.setChunked(false);
        response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
        response.headers().set(Exchange.CONTENT_LENGTH, 0);
        ctx.writeAndFlush(response);
        ctx.channel().close();
        return;
    }
    // is basic auth configured
    NettyHttpSecurityConfiguration security = consumer.getEndpoint().getSecurityConfiguration();
    if (security != null && security.isAuthenticate() && "Basic".equalsIgnoreCase(security.getConstraint())) {
        String url = request.uri();
        // drop parameters from url
        if (url.contains("?")) {
            url = ObjectHelper.before(url, "?");
        }
        // we need the relative path without the hostname and port
        URI uri = new URI(request.uri());
        String target = uri.getPath();
        // strip the starting endpoint path so the target is relative to the endpoint uri
        String path = consumer.getConfiguration().getPath();
        if (path != null && target.startsWith(path)) {
            // need to match by lower case as we want to ignore case on context-path
            path = path.toLowerCase(Locale.US);
            String match = target.toLowerCase(Locale.US);
            if (match.startsWith(path)) {
                target = target.substring(path.length());
            }
        }
        // is it a restricted resource?
        String roles;
        if (security.getSecurityConstraint() != null) {
            // if restricted returns null, then the resource is not restricted and we should not authenticate the user
            roles = security.getSecurityConstraint().restricted(target);
        } else {
            // assume any roles is valid if no security constraint has been configured
            roles = "*";
        }
        if (roles != null) {
            // basic auth subject
            HttpPrincipal principal = extractBasicAuthSubject(request);
            // authenticate principal and check if the user is in role
            Subject subject = null;
            boolean inRole = true;
            if (principal != null) {
                subject = authenticate(security.getSecurityAuthenticator(), security.getLoginDeniedLoggingLevel(), principal);
                if (subject != null) {
                    String userRoles = security.getSecurityAuthenticator().getUserRoles(subject);
                    inRole = matchesRoles(roles, userRoles);
                }
            }
            if (principal == null || subject == null || !inRole) {
                if (principal == null) {
                    LOG.debug("Http Basic Auth required for resource: {}", url);
                } else if (subject == null) {
                    LOG.debug("Http Basic Auth not authorized for username: {}", principal.getUsername());
                } else {
                    LOG.debug("Http Basic Auth not in role for username: {}", principal.getUsername());
                }
                // restricted resource, so send back 401 to require valid username/password
                HttpResponse response = new DefaultHttpResponse(HTTP_1_1, UNAUTHORIZED);
                response.headers().set("WWW-Authenticate", "Basic realm=\"" + security.getRealm() + "\"");
                response.headers().set(Exchange.CONTENT_TYPE, "text/plain");
                response.headers().set(Exchange.CONTENT_LENGTH, 0);
                ctx.writeAndFlush(response);
                // close the channel
                ctx.channel().close();
                return;
            } else {
                LOG.debug("Http Basic Auth authorized for username: {}", principal.getUsername());
            }
        }
    }
    // let Camel process this message
    super.channelRead0(ctx, msg);
}
Also used : HttpRequest(io.netty.handler.codec.http.HttpRequest) NettyHttpSecurityConfiguration(org.apache.camel.component.netty4.http.NettyHttpSecurityConfiguration) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) HttpResponse(io.netty.handler.codec.http.HttpResponse) URI(java.net.URI) HttpPrincipal(org.apache.camel.component.netty4.http.HttpPrincipal) Subject(javax.security.auth.Subject)

Aggregations

URI (java.net.URI)2 DefaultHttpResponse (io.netty.handler.codec.http.DefaultHttpResponse)1 HttpRequest (io.netty.handler.codec.http.HttpRequest)1 HttpResponse (io.netty.handler.codec.http.HttpResponse)1 HashMap (java.util.HashMap)1 Subject (javax.security.auth.Subject)1 Endpoint (org.apache.camel.Endpoint)1 NettyConfiguration (org.apache.camel.component.netty4.NettyConfiguration)1 NettyServerBootstrapConfiguration (org.apache.camel.component.netty4.NettyServerBootstrapConfiguration)1 HttpPrincipal (org.apache.camel.component.netty4.http.HttpPrincipal)1 NettyHttpSecurityConfiguration (org.apache.camel.component.netty4.http.NettyHttpSecurityConfiguration)1 HeaderFilterStrategy (org.apache.camel.spi.HeaderFilterStrategy)1