Apache Camel 2.14 Rest DSL Security

社会主义新天地 提交于 2019-12-03 20:52:02

Two options.

  1. You can use basic auth with jetty rest DSL. I just spent some time working with basic auth, a jetty rest DSL service, and camel 2.15. I wrote up my experiences here: http://www.mooreds.com/wordpress/archives/2065 . I found the camel-jetty wiki page a bit out of date, full code here: https://github.com/mooreds/camel-rest-jetty-auth

  2. You can use spring security (at least with version 2.15.2 of camel and 4.0.1.RELEASE of spring security, which is what I am using). To do so, you need to make sure you create a processor class, as outlined here: http://camel.apache.org/spring-security.html#SpringSecurity-Authentication and put it in front of every route before you call the policy. You also need to create an exception handler to present a nice message to an unauthorized user--here's what I did in my java routebuilder: onException(org.apache.camel.CamelAuthorizationException.class).handled(true).transform(simple("Access Denied with the Policy of ${exception.policyId} !")).setHeader(Exchange.HTTP_RESPONSE_CODE, simple("401"));

Here is how I solved it using Apache Camel 2.15.2. I use this backend together with an AngularJS frontent where I use an httpInterceptor to add the authenitcation header. I use JWT to store a tenantId in the authorization header. This tenantId is used together with Hibernate and its Multi Tenancy Support.

Front end login controller, using AngularJs and written in 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));
        }
    }
}

This is the class JwtService that is responsible for creating a JWT Token:

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

To use this in a route I define it like this:

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

Taken from https://camel.apache.org/jetty.html

Jetty handlers and security configuration

You can configure a list of Jetty handlers on the endpoint, which can be useful for enabling advanced Jetty security features. These handlers are configured in Spring XML as follows:

<-- 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>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!