2012-02-29 17 views
1

hereのように、プログラムでJettyサーバーの基本認証を実装したいとします。利便性のために、私はここでそのスニペットをV'ingしています。Camel Jettyとの基本認証

import org.mortbay.jetty.security.*; 

Server server = new Server(); 

Connector connector = new SelectChannelConnector(); 
connector.setPort(8080); 
server.setConnectors(new Connector[]{connector}); 

Constraint constraint = new Constraint(); 
constraint.setName(Constraint.__BASIC_AUTH);; 
constraint.setRoles(new String[]{"user","admin","moderator"}); 
constraint.setAuthenticate(true); 

ConstraintMapping cm = new ConstraintMapping(); 
cm.setConstraint(constraint); 
cm.setPathSpec("/*"); 

SecurityHandler sh = new SecurityHandler(); 
sh.setUserRealm(new HashUserRealm("MyRealm",System.getProperty("jetty.home")+"/etc/realm.properties")); 
sh.setConstraintMappings(new ConstraintMapping[]{cm}); 

WebAppContext webappcontext = new WebAppContext(); 
webappcontext.setContextPath("/mywebapp"); 
webappcontext.setWar("./path/to/my/war/orExplodedwar"); 
webappcontext.addHandler(sh); 

HandlerCollection handlers= new HandlerCollection(); 
handlers.setHandlers(new Handler[]{webappcontext, new DefaultHandler()}); 

server.setHandler(handlers); 
server.start(); 
server.join(); 

ここで問題になるのは、上記の方法ではサーバーへのハンドルが必要だということです。しかし、私の場合はCamelを使用しているため、サーバーに直接アクセスすることはできません。これは私のパイプラインが定義されている方法です。

from("jetty:http://localhost:8080/documents_in?matchOnUriPrefix=true"). 
    process(new MyProcessor()); 

は、どのように私は私の場合にリンクされた認証ソリューションを適応させるのですか?それとも全く別の方法に従わなければならないのですか?

私はCamelとJetty初心者の両方です。どんな助けでも大歓迎です。ありがとう。

補遺:

This page私たちに役に立たないののように、しかし、我々は、春を使用していない、春のXMLでそれを行う方法を示しています。

答えて

0

CamelのJettyComponentには、Javaコードでこれを設定できるgetter/setterがあります。

JettyComponent jetty = new JettyComponent(); 
// use getter/setter to configure 
// add component to Camel 
camelContext.addComponent("jetty", jetty); 
// after this you can add the routes and whatnot 
1

私は数日前にこの問題に出くわし、私は必要とBasicAuthenticatorは、認証の世話をカスタマイズLoginServiceを使用していますConstraintSecurityHandlerの独自の実装を定義することによってこの問題を解決しました。 Bean管理の認証を扱うことができる既存のLoginService実装が見つからなかったので、私はこの解決策を考え出す必要がありました。

プライベートにしなければならない内部のものを除いて、ほぼ完全なクラスを投稿します。

import java.security.Principal; 

import javax.annotation.Resource; 
import javax.security.auth.Subject; 

import org.eclipse.jetty.security.ConstraintMapping; 
import org.eclipse.jetty.security.ConstraintSecurityHandler; 
import org.eclipse.jetty.security.DefaultIdentityService; 
import org.eclipse.jetty.security.IdentityService; 
import org.eclipse.jetty.security.LoginService; 
import org.eclipse.jetty.security.MappedLoginService; 
import org.eclipse.jetty.security.authentication.BasicAuthenticator; 
import org.eclipse.jetty.server.UserIdentity; 
import org.eclipse.jetty.util.security.Constraint; 
import org.eclipse.jetty.util.security.Credential; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

import com.google.common.base.Strings; 

/** 
* <p> 
* Sets up a basic authentication mechanism for REST based services exposed via 
* Jetty for our REST API (http(s)://server:port/api/v1/...). 
* </p> 
* <p> 
* It moreover defines a login service which is capable of using an internal 
* persistence layer for authenticating a user and his credentials received via 
* a challenge response against a user entity retrieved via the persistence 
* layer. 
* </p> 
*/ 
public class JettyBasicAuthAuthorizationHandler extends ConstraintSecurityHandler 
{ 
    /** The logger of this class **/ 
    private static final Logger logger = 
      LoggerFactory.getLogger(JettyBasicAuthAuthorizationHandler.class); 

    /** The persistence service to retrieve the user informations from **/ 
    @Resource 
    private ISomePersistenceService persistenceService; 

    private final String[] roles = new String[] {"user"}; 

    /** 
    * <p> 
    * Initializes a Jetty based Basic Authentication mechanism. 
    * </p> 
    */ 
    public JettyBasicAuthAuthorizationHandler() 
    { 
     super(); 

     // Specifies the challenge to be of type BASIC and that users have 
     // to fulfill one of the roles listed in roles. Moreover authentication 
     // is required 
     Constraint constraint = new Constraint(); 
     constraint.setName(Constraint.__BASIC_AUTH); 
     constraint.setRoles(this.roles); 
     constraint.setAuthenticate(true); 

     // Map the defined constraints from above to the services provided via 
     // our REST API 
     ConstraintMapping cm = new ConstraintMapping(); 
     cm.setConstraint(constraint); 
     cm.setPathSpec("/api/v1/*"); 

     // BasicAuthenticator takes care of sending a challenge to the caller 
     // and calls our login service in case of a challenge response to 
     // evaluate if the user is permitted to use the service. 
     // The realm name defines the name of the login service which should be 
     // used for authentication. 
     BasicAuthenticator basic = new BasicAuthenticator(); 
     this.setAuthenticator(basic); 
     this.addConstraintMapping(cm); 
     this.setRealmName("REST"); 
     this.setLoginService(new BeanManagedLoginService("REST")); 

     logger.debug("JettyBasicAuthAuthorizationHandler created!"); 
    } 

    /** 
    * <p> 
    * Implements a bean managed login service where an authentication response 
    * is propagated to a business layer bean which retrieves the user and 
    * credentials from a backing data store. 
    * </p> 
    */ 
    class BeanManagedLoginService implements LoginService 
    {  
     /** An identity service used to create a UserIdentity object for us **/ 
     private IdentityService identityService = new DefaultIdentityService(); 

     private String name = "REST"; 

     /** 
     * <p> 
     * Initializes a new instance. 
     * </p> 
     */ 
     public BeanManagedLoginService() 
     { 

     } 

     /** 
     * <p> 
     * Initializes a new instance and sets the realm name this login service 
     * will work for. 
     * </p> 
     * 
     * @param name The name of this login service (also known as the realm it 
     *    will work for) 
     */ 
     public BeanManagedLoginService(String name) 
     { 
      this.name = name; 
     } 

     /** 
     * <p> 
     * Returns the name of the login service (the realm name) 
     * </p> 
     * 
     * @return Get the name of the login service (aka Realm name) 
     */ 
     @Override 
     public String getName() 
     { 
      return this.name; 
     } 

     /** 
     * <p> 
     * Logs in a user by checking the username with known users and 
     * comparing the credentials with the stored ones. If the user could not 
     * be authenticated successfully an unauthenticated user identity will 
     * be returned. 
     * </p> 
     * 
     * @param username The user name as sent by the ChallengeResponse 
     * @param credentials The credentials provided in the ChallengeResponse 
     * 
     * @return If the user could be authenticated successfully a valid 
     * {@link UserIdentity}, else an unauthorized user identity 
     */ 
     @Override 
     public UserIdentity login(String username, Object credentials) 
     { 
      if (logger.isDebugEnabled()) 
       logger.debug("received login request for user: '{}' with credentials: '{}'!", 
        username, credentials); 

      // check if the username is valid 
      if (!Strings.isNullOrEmpty(username)) 
      { 
       String password = credentials.toString(); 

       // retrieve the user from the business layer 
       final UserEntity sue = persistenceService.findUser(username); 
       if (sue == null) 
       { 
        if (logger.isErrorEnabled()) 
         logger.error("No User could be found for UserId '{}'. The UserKey (which was not checked) is '{}'", 
          username, password); 
        return UserIdentity.UNAUTHENTICATED_IDENTITY; 
       } 
       // check whether the password matches the one in the user entity 
       // found for the user id 
       if (password.equals(sue.getUserKey())) 
       { 
        // the user could be successfully authenticated 
        if (logger.isDebugEnabled()) 
         logger.debug("UserKey {} of User {} was successfully authenticated", 
          sue.getUserKey(), sue.getUserId()); 

        if (logger.isDebugEnabled()) 
         logger.debug("User '{}'/'{}' works for '{}'", 
           userId, userName, sue.getCompany().getName()); 
        return this.createIdentityForUser(username, password); 
       } 
       else 
       { 
        // the password set in the request and the one stored in the 
        // user entity do not match 
        if (logger.isErrorEnabled()) 
         logger.error(
          "User {} could not be authenticated. The UserKey in the user entity is {} but the UserKey in the request was {}", 
          new Object[] { username, sue.getUserKey(), password }); 
        return UserIdentity.UNAUTHENTICATED_IDENTITY; 
       }    
      } 
      else 
      { 
       if (logger.isErrorEnabled()) 
        logger.error("Username is empty and therefore could not get authenticated correctly"); 
       return UserIdentity.UNAUTHENTICATED_IDENTITY; 
      } 
     } 

     /** 
     * <p> 
     * Creates a UserIdentity object for a successfully authenticated user. 
     * </p> 
     * 
     * @param username The name of the authenticated user 
     * @param password The password of the authenticated user 
     * 
     * @return A valid UserIdentity object 
     */ 
     private UserIdentity createIdentityForUser(String username, String password) 
     { 
      // create a principal object needed for the user identity 
      Credential cred = Credential.getCredential(password); 
      // a principal is basically an identity of a real person 
      // (subject). So a user can have multiple principals 
      Principal userPrincipal = new MappedLoginService.KnownUser(username, cred); 

      // a subject collects all data necessary to identify a certain 
      // person. It may store multiple identities and passwords or 
      // cryptographic keys 
      Subject subject = new Subject(); 
      // add a Principal and credential to the Subject 
      subject.getPrincipals().add(userPrincipal); 
      subject.getPrivateCredentials().add(cred); 
      subject.setReadOnly(); 

      return this.identityService.newUserIdentity(subject, userPrincipal, roles); 
     } 

     /** 
     * <p> 
     * Validate just checks if a user identity is still valid. 
     * </p> 
     */ 
     @Override 
     public boolean validate(UserIdentity user) 
     { 
      return true; 
     } 

     @Override 
     public IdentityService getIdentityService() 
     { 
      return this.identityService; 
     } 

     @Override 
     public void setIdentityService(IdentityService service) 
     { 
      this.identityService = service; 
     } 

     @Override 
     public void logout(UserIdentity user) 
     { 

     } 
    } 
} 

あなたはこのように、このハンドラを使用してエンドポイントを定義することができキャメルの組み込みのJettyサーバにこのハンドラを追加するには: - あなたが使用していない場合はjettyAuthHandlerはこのハンドラのBean名です

jetty:https://your-server:port/api/v1/yourService?sslContextParameters=#sslContextParameters&handlers=#jettyAuthHandler 

SSLはsslContextParametersパラメータを省略するだけです。

+0

これを共有してくれてありがとうございます。 CamelのHTTP機能をテストするためにコードを使用しても問題ありませんか? camel-httpを使用してアウトバウンドHTTP呼び出しを行う実行環境があります。 camel-http4への移行を計画しているので、私は実際のライブ環境のテストケースを十分に持ちたいと思っていました。テストケースについては、JettyにBasic Auth(コードを使用)をホストし、テストケースでアウトバウンドコールを実行しています。あなたのコードを使用して予約がある場合は、私に知らせてください。 – Robin

+0

@Robin好きなようにコードを自由に使うことができます。コードを投稿した時点で、SOはCC-BY-SAライセンスを維持していましたが、現在は[MITライセンス]に変更されています(http://meta.stackexchange.com/questions/271080/the-mit-license-clarity- on-use-on-using-code-on-stack-overflow-and-stack-exchange)を使用して実行されます。私はそれ故、私の古い投稿の全てをMITとも見なす(実際にそうする権利があるのか​​どうかは分からない^^) –

+0

ありがとう。 MITライセンスを追加しました(コードはテスト用です)。また、あなたのコードでは、Jetty :: JAASライブラリを使用してX509証明書を検証するためのログインサービスも用意されています。私がキャメル桟橋で走ることができるかどうか見てみましょう。 – Robin