当前位置: 首页 > 知识库问答 >
问题:

Apache Camel 2.14 Rest DSL安全

缪英锐
2023-03-14

我想使用Apache Camel 2.14中新的Rest DSL来创建一个Rest接口。我想使用Jetty组件,我有一个基本的示例设置,如下所示:

Spring Security配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:spring-security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
      http://camel.apache.org/schema/spring-security http://camel.apache.org/schema/spring-security/camel-spring-security.xsd
      http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">


<spring-security:http auto-config="true" use-expressions="true" >
    <spring-security:intercept-url pattern="/**" access="isFullyAuthenticated()"/>
    <spring-security:http-basic></spring-security:http-basic>
</spring-security:http>

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
    <property name="allowIfAllAbstainDecisions" value="true"/>
    <property name="decisionVoters">
        <list>
            <bean class="org.springframework.security.access.vote.RoleVoter"/>
        </list>
    </property>
</bean>


<spring-security:authentication-manager alias="authenticationManager">
    <spring-security:authentication-provider user-service-ref="userDetailsService"/>
</spring-security:authentication-manager>


<spring-security:user-service id="userDetailsService">
    <spring-security:user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN"/>
    <spring-security:user name="user" password="user" authorities="ROLE_USER"/>
</spring-security:user-service>


<authorizationPolicy id="admin" access="ROLE_ADMIN"
                     authenticationManager="authenticationManager"
                     accessDecisionManager="accessDecisionManager"
                     xmlns="http://camel.apache.org/schema/spring-security"/>

<authorizationPolicy id="user" access="ROLE_USER"
                     xmlns="http://camel.apache.org/schema/spring-security"/>

驼峰路线配置

restConfiguration().component("jetty").host("0.0.0.0").port(24999).bindingMode(RestBindingMode.json).dataFormatProperty("prettyPrint", "true");

    rest("address").description("Contains services for addresses").
            consumes("application/json").
            produces("application/json").
            get().      
            route().policy("admin").
            to("bean:restAddressApi?method=queryAddress").endRest();

当我尝试使用wget访问此受保护的URL时:

 wget --http-user=admin --http-password=admin http://localhost:24999/address/

然后我在控制台中得到这个错误:

org.apache.camel.CamelAuthorizationException: Cannot find the Authentication instance.. Exchange[Message: [Body is null]]
at org.apache.camel.component.spring.security.SpringSecurityAuthorizationPolicy.beforeProcess(SpringSecurityAuthorizationPolicy.java:72)
at org.apache.camel.component.spring.security.SpringSecurityAuthorizationPolicy$AuthorizeDelegateProcess.process(SpringSecurityAuthorizationPolicy.java:120)
at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:416)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:118)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:80)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
at org.apache.camel.component.jetty.CamelContinuationServlet.service(CamelContinuationServlet.java:150)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:503)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:429)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
at org.eclipse.jetty.server.handler.ResourceHandler.handle(ResourceHandler.java:406)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
at org.eclipse.jetty.server.Server.handle(Server.java:370)
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494)
at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:971)
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:1033)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:644)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235)
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:696)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:53)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
at java.lang.Thread.run(Thread.java:745)

我的配置中缺少了什么来让它工作?

共有3个答案

程吕恭
2023-03-14

取自https://camel.apache.org/jetty.html

Jetty处理程序和安全配置

您可以在endpoint上配置Jetty处理程序列表,这对于启用高级Jetty安全功能非常有用。这些处理程序在Spring XML中配置如下:

<-- Jetty Security handling -->
<bean id="userRealm" class="org.mortbay.jetty.plus.jaas.JAASUserRealm">
    <property name="name" value="tracker-users"/>
    <property name="loginModuleName" value="ldaploginmodule"/>
</bean>

<bean id="constraint" class="org.mortbay.jetty.security.Constraint">
    <property name="name" value="BASIC"/>
    <property name="roles" value="tracker-users"/>
    <property name="authenticate" value="true"/>
</bean>

<bean id="constraintMapping" class="org.mortbay.jetty.security.ConstraintMapping">
    <property name="constraint" ref="constraint"/>
    <property name="pathSpec" value="/*"/>
</bean>

<bean id="securityHandler" class="org.mortbay.jetty.security.SecurityHandler">
    <property name="userRealm" ref="userRealm"/>
    <property name="constraintMappings" ref="constraintMapping"/>
</bean>
权兴为
2023-03-14

这是我使用Apache Camel 2.15.2解决它的方法。我将此后端与AngularJS前端一起使用,其中我使用httpInterceptor添加Authenitcation标头。我使用JWT在授权标头中存储tenantId。此tenantId与Hibernate及其多租户支持一起使用。

前端登录控制器,使用AngularJs并用TypeScript编写:

 /// <reference path="../reference.ts"/>
module Controllers {

  export class Credentials {
    username:string;
    password:string;
  }

  export interface ILoginControllerScope extends ng.IScope {
    credentials:Credentials;
    login:()=>void;
  }

  export class LoginController {
    private _scope:ILoginControllerScope;

    static $inject = ['$scope', '$http', 'UserService', '$location'];

    constructor($scope:ILoginControllerScope, $http:ng.IHttpService, UserService:UserService, $location:ng.ILocationService) {
      this._scope = $scope;
      $scope.credentials = new Credentials();

      $scope.login = ()=> {
        $http.post('/api/authenticate', $scope.credentials)
          .success(function (data:string, status:any, headers:any, config:any) {
            // Remove all " characters from string.
            data = data.replace(/"/gi, '');
            UserService.setSecurityToken(data);
            $location.path('/');
          })
          .error(function (data:any, status:any, headers:any, config:any) {

          });
      }
    }
  }
}



 @Override
    public void process(Exchange exchange) throws Exception {
        Map<String, String> credentials = exchange.getIn().getBody(HashMap.class);
    String username = credentials.get("username");
    String password = credentials.get("password");

        // Login logic that returns object() containing user info
        exchange.getIn().setBody(jwtService.generateToken(tenantConfiguration));
        }
    }
}

这是负责创建JWT令牌的JwtService类:

package com.me.services;

import com.me.TenantConfiguration;
import com.google.common.collect.Maps;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.security.SecureRandom;
import java.util.Map;
import java.util.Random;

@Service
public class JwtService {

    public static final String TENANT_ID = "tenant_id";
    public static final String ROLE = "role";

    @Value("${jwt.subject}")
    private String jwtSubject;

    private byte[] signingKey;

    private SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

    public SignatureAlgorithm getSignatureAlgorithm() {
        return signatureAlgorithm;
    }

    public byte[] getSigningKey() {
        if (this.signingKey == null) {
            // Generate new signingKey
            Random random = new SecureRandom();
            signingKey = new byte[64];
            random.nextBytes(signingKey);
        }
        return this.signingKey;
    }

    public String getJwtSubject() {
        return jwtSubject;
    }

    public String generateToken(TenantConfiguration tenantConfiguration){
        Map<String, Object> claims = Maps.newHashMap();
        claims.put(TENANT_ID, tenantConfiguration.getSessionId());
        String token = Jwts.builder().setSubject(this.getJwtSubject()).setClaims(claims).signWith(this.getSignatureAlgorithm(), this.getSigningKey()).compact();
        return token;
    }
}

要在路由中使用它,我这样定义它:

        rest("api/messages").description("Restful API for messages").
            get().id("GetMessages").route().to("springSecurityContextLoader").policy(authorizationPolicy).to("bean:restMessageApi?method=getAllMessages").endRest().

SpringSecurityContextloader

@Service
public class SpringSecurityContextLoader implements Processor {
@Inject
private JwtService jwtService;

@Override
public void process(Exchange exchange) throws Exception {

    String authorization = exchange.getIn().getHeader("Authorization", String.class);

    Jwt jwt = Jwts.parser().setSigningKey(jwtService.getSigningKey()).parse(authorization);

    Map<String, Object> claims = (Map<String, Object>) jwt.getBody();
    String tenantId = claims.get(JwtService.TENANT_ID).toString();

    Authentication authentication = new PreAuthenticatedAuthenticationToken(tenantId, "something", Lists.newArrayList(new SimpleGrantedAuthority("ROLE_USER")));

    SecurityContextHolder.getContext().setAuthentication(authentication);
}
岳意蕴
2023-03-14

有两个选择。

>

  • 您可以将basic auth与jetty rest DSL结合使用。我只是花了一些时间使用basic auth、jetty rest DSL服务和camel 2.15。我在这里写下了我的经历:http://www.mooreds.com/wordpress/archives/2065.我发现camel jetty wiki页面有点过时,完整代码如下:https://github.com/mooreds/camel-rest-jetty-auth

    您可以使用Spring Security性(至少在camel的2.15.2版本和Spring Security性的4.0.1.RELEASE版本中使用,这就是我正在使用的)。为此,您需要确保创建一个processor类,如下所述:http://camel.apache.org/spring-security.html" target="_blank">html#SpringSecurity-在调用策略之前,验证并将其放在每条路由的前面。您还需要创建一个异常处理程序来向未经授权的用户呈现一条好消息——以下是我在java routebuilder中所做的:OneException(org.apache.camel.CamelAuthorizationException.class)。处理(正确)。转换(简单(“使用${exception.policyId}策略拒绝访问!”)。setHeader(Exchange.HTTP_RESPONSE_代码,简单(“401”)

  •  类似资料:
    • 安全在Web应用开发中是一项至关重要的话题,Django提供了多种保护手段和机制:

    • Elasticsearch-PHP 客户端支持两种安全设置方式:HTTP 认证和 SSL 加密。 HTTP 认证 如果你的 Elasticsearch 是通过 HTTP 认证来维持安全,你就要为 Elasticsearch-PHP 客户端提供身份凭证(credentials),这样服务端才能认证客户端请求。在实例化客户端时,身份凭证(credentials)需要配置在 host 数组中: $hos

    • 安全 no_file_caps 要求内核无视文件的权限。这样,执行文件的唯一途径就只有:由root去执行或者setuid root noexec={on|off} noexec32={on|off} 是否允许将某部分内存映射为"禁止执行",这是一种防止数据缓冲区溢出攻击的保护措施(也就是WinXP SP2曾经大力宣传的数据执行保护功能),建议保持默认值"on"。 [说明]noexec对32bit代

    • 请参考:http://www.kancloud.cn/manual/thinkphp/1840

    • 评估 Docker 的安全性时,主要考虑三个方面: 由内核的命名空间和控制组机制提供的容器内在安全 Docker 程序(特别是服务端)本身的抗攻击性 内核安全性的加强机制对容器安全性的影响

    • 本节详细介绍了Web容器包含在一个产品中时额外的安全性要求,还包含EJB、JACC和(或)JASPIC。以下各节将介绍这些要求。 EJB™调用传播的安全标识 必须始终提供一个安全标识或主体(principal),用于调用一个企业 bean。从 Web 应用程序中调用企业 Bean 的默认模式是为把 Web 用户的安全标识传播到 EJB 容器。 在其他情况下,Web 容器必须允许不了解 Web 容器

    • 应用开发人员创建Web应用,他给、销售或其他方式转入应用给部署人员,部署人员覆盖安装到运行时环境。应用开发人员与部署人员沟通部署系统的安全需求。该信息可以通过应用部署描述符声明传达,通过在应用代码中使用注解,或通过 ServletRegistration 接口的setServletSecurity 方法编程。 本节描述了 Servlet 容器安全机制、接口、部署描述符和基于注解机制和编程机制用于传

    • 安全工具 Coding tool: DOMPurity XSS References: HTML5 Security Cheatsheet