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;
}
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);
}
Aggregations