2012-02-29 4 views
1

Я хочу программно реализовать базовую аутентификацию для сервера Jetty, как показано на рисунке here. Ради удобства, я здесь^C-^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()); 

Как адаптировать связанное решение для аутентификации к моему делу? Или мне нужно следовать совсем другому методу?

Обратите внимание, что я являюсь как новичком верблюда, так и новичком. Любая помощь будет оценена. Благодарю.

Добавление:

This page показывает, как сделать это с Spring XML, однако мы не используем Spring, так что это не имеет смысла для нас.

ответ

0

В JettyComponent в Camel есть getter/setter, где вы можете настроить это в Java-коде.

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

я наткнулся на эту проблему пару дней назад, и я решил эту проблему, определив собственную реализацию ConstraintSecurityHandler, который использует настраиваемую LoginService, который заботится о подлинности BasicAuthenticator требует. Поскольку я не нашел никакой существующей реализации 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 верблюжьего можно определить конечную точку с помощью этого обработчика, как это:

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

где jettyAuthHandler это имя боб этого обработчика - если вы не используете SSL просто опускает параметр sslContextParameters.

+0

Спасибо, Роман за это. Это нормально, если я использовал ваш код для тестирования моей функциональности на верблюде? У меня запущена среда, в которой исходящие HTTP-вызовы выполняются с помощью camel-http. Поскольку мы планируем перейти на верблюд-http4, я хотел бы иметь достаточные тестовые примеры нашей реальной живой среды. В тестовых случаях я принимаю Jetty с Basic Auth (используя ваш код) и запускаю исходящие вызовы в тестовом примере. Дайте мне знать, если у вас есть какая-либо оговорка в использовании вашего кода. – Robin

+0

@Robin Не стесняйтесь использовать код, как вам нравится. В то время, когда я опубликовал код, SO сохранила лицензию CC-BY-SA на должности, но теперь изменилась на [лицензию MIT] (http://meta.stackexchange.com/questions/271080/the-mit-license-clarity- на использовании-кода-на-стека переполнение-и-стек-обмен). Поэтому я рассматриваю все мои старшие должности также как MIT (не уверен, что я даже имею право делать это на самом деле ^^) –

+0

Большое спасибо. Я добавил лицензию MIT (хотя код предназначен только для тестирования). Кроме того, ваш код дал идею даже иметь службу входа в систему для проверки сертификатов X509 с использованием библиотеки Jetty :: JAAS. Посмотрим, смогу ли я работать с Camel Jetty. – Robin

Смежные вопросы