2016-09-19 4 views
1

Ich bin dabei, zwei Servlets zu einem eingebetteten Tomcat hinzuzufügen. In diesem Szenario sollte eines der Servlets durch die Standardauthentifizierung "geschützt" werden. Ich möchte die Sicherheitsbeschränkungen nur über Code hinzufügen. In Bezug auf diese Link sollte es nicht zu schwer sein.Eingebetteter Tomcat mit einfacher Authentifizierung über Code

Ich baue ein Testszenario:

Projekt: EmbeddedTomcatTest

-Source Packages 
--tomcat.test 
---ServletOne.java 
---ServletTwo.java 
---StartEmbeddedTomcat.java (contains main method) 
-Test Packages 
-Other Sources 
--src/main/resources 
---Tomcat-users.xml 
-Project Files 
--pom.xml 

Die Abhängigkeiten meiner pom wie folgt aussieht:

<dependencies> 
     <dependency> 
      <groupId>org.apache.tomcat.embed</groupId> 
      <artifactId>tomcat-embed-core</artifactId> 
      <version>8.5.4</version> 
     </dependency> 
     <dependency> 
      <groupId>javax.servlet</groupId> 
      <artifactId>javax.servlet-api</artifactId> 
      <version>3.1.0</version> 
     </dependency> 
    </dependencies> 

Bisher habe ich ein eingebettetes Kater mit zwei Servlets hinzugefügt, sind über verschiedene URL-Muster zugänglich, was gut funktioniert.

public class StartEmbeddedTomcat { 
    private static final String AUTH_ROLE = "test"; 

    public static void main(String[] args) throws LifecycleException { 
    Tomcat tomcat = new Tomcat(); 
    tomcat.setPort(8080); 
    // adding a context 
    Context ctx = tomcat.addContext("/", new File(".").getAbsolutePath()); 

    // Login Config 
    LoginConfig config = new LoginConfig(); 
    config.setAuthMethod("BASIC");  

    // adding constraint with role "test" 
    SecurityConstraint constraint = new SecurityConstraint(); 
    constraint.addAuthRole(AUTH_ROLE); 

    // add constraint to a collection with pattern /second 
    SecurityCollection collection = new SecurityCollection(); 
    collection.addPattern("/second"); 
    constraint.addCollection(collection); 

    ctx.setLoginConfig(config); 
    // does the context need a auth role too? 
    ctx.addSecurityRole(AUTH_ROLE); 
    ctx.addConstraint(constraint); 

    // add servlet with pattenr /first and /second 
    Tomcat.addServlet(ctx, "one", new ServletOne()); 
    ctx.addServletMapping("/first", "one"); 

    Tomcat.addServlet(ctx, "two", new ServletTwo()); 
    ctx.addServletMapping("/second", "two"); 

    // add tomcat users to realm 
    String path = "tomcat-users.xml"; 
    URL uri = ServletOne.class.getClassLoader().getResource(path); 
    MemoryRealm realm = new MemoryRealm(); 
    realm.setPathname(uri.toString()); 
    tomcat.getEngine().setRealm(realm); 
    tomcat.start(); 
    tomcat.getServer().await(); 
    } 
} 

Die tomcat-users.xml ist nicht besonders.

<tomcat-users> 
    <role rolename="manager-gui"/> 
    <role rolename="test"/> 

    <user name="admin" password="" roles="manager-gui"/> 
    <user name="test" password="test" roles="test"/> 
</tomcat-users> 

Ich denke, der Code der Servlets nicht wichtig ist, da sie nur "Im Servlet-one" oder "Im Servlet zwei" -Antwort.

Meiner Meinung nach sollte die ganze Anwendung oder zumindest jede Anfrage auf /second geschützt werden. Was habe ich falsch gemacht? Gibt es noch etwas, was ich tun muss?

---- bearbeiten ---

Heute fand ich diese question von Stack-Überlauf. Ich habe noauthCTX.setAltDDName("Path\\to\\web.xml"); zu meinem Testszenario hinzugefügt. Die web.xml wie folgt aussieht:

<web-app> 
    <display-name>Test Service</display-name> 
    <servlet> 
     <servlet-name>ServletOne</servlet-name> 
     <servlet-class>tomcat.test.test.ServletOne</servlet-class> 
     <load-on-startup>1</load-on-startup> 
    </servlet> 
    <servlet-mapping> 
     <servlet-name>ServletOne</servlet-name> 
     <url-pattern>/servletOne/*</url-pattern> 
    </servlet-mapping> 
</web-app> 

Ich dachte, mein Servlet würde man über localhost:8080/servletOne/* auch zugänglich sein. Es ist nicht .. eigentlich bin ich sehr verwirrt. Ich hoffe jemand kann mir helfen ..

Antwort

0

Das Problem ist, dass Sie versuchen, einen Kontext zu sichern. Ein Kontext ist nicht festlegbar, dh

tomcat.addContext("/", new File(".").getAbsolutePath());

Muss

tomcat.addWebapp("/", new File(".").getAbsolutePath());

Sie müssen befassen sich mit einigen Ausnahmebehandlung, weil das Hinzufügen einer neuen Web-App kann geändert werden Werfen Sie eine ServletException, aber dennoch sollte es danach arbeiten, wie Sie erwarten.

Wenn Sie die Standardwerte (z. B. MIME-Typzuordnungen, Servlet für statische Inhalte, JSP, ...) nicht laden möchten, können Sie einfach die Methode getDefaultWebXmlListener überschreiben.

tomcat = new Tomcat() { 

    @Override 
    public LifecycleListener getDefaultWebXmlListener() { 
     return event -> {}; 
    } 
}; 
0

Wahrscheinlich ist es ein wenig spät, diese Frage zu beantworten, aber es kann für andere nützlich sein. Kürzlich sah ich mich einem ähnlichen Problem gegenüber, als ich versuchte, die Sicherheit für eingebettete Tomcat mit SpringBoot zu konfigurieren, Sicherheitseinschränkungen funktionierten einfach nicht und mein Realm wurde überhaupt nicht aufgerufen. Das Problem stellte sich in org.apache.catalina.authenticator.SSLAuthenticator dar, dieses Ventil wurde nicht zur Tomcat-Pipeline hinzugefügt und somit wurden SecurityConstraints nicht überprüft.

Hinzufügen tomcatFactory.addContextValves(new SSLAuthenticator()); löste das Problem.

Wenn Sie die Standardauthentifizierung Ventil Klasse ist

org.apache.catalina.authenticator.BasicAuthenticator

Voll funktions Konfiguration für Zwei-Wege-SSL und Sicherheitsbereich auf Embedded tomcat:

Java Config

@Configuration 
public class EmbeddedTomcatConfiguration { 

    private static final String LOGIN_CONFIG_AUTH_METHOD = "CLIENT-CERT"; 

    @Bean 
    public RealmBase createPkiRealm() { 
     //Create your custom realm or use some standard one here 
     return realm; 
    } 

    @Bean 
    public EmbeddedServletContainerCustomizer createTomcatCustomizer(RealmBase pkiRealm) { 
     return (container) -> { 
      TomcatEmbeddedServletContainerFactory tomcatFactory = (TomcatEmbeddedServletContainerFactory) container; 
      //tomcatFactory.addAdditionalTomcatConnectors(createSslConnector()); //connector is configured in application.properties 
      tomcatFactory.addContextCustomizers(createTomcatContextCustomizer(pkiRealm)); 
      tomcatFactory.addEngineValves(new SingleSignOn()); 
      tomcatFactory.addContextValves(new SSLAuthenticator()); //this is where PKI realm is invoked 
     }; 
    } 

    private TomcatContextCustomizer createTomcatContextCustomizer(RealmBase pkiRealm) { 
     return (context) -> { 
      context.setRealm(pkiRealm); 
      context.setLoginConfig(createLoginConfig()); 
      context.addSecurityRole("new_role"); 
      context.addConstraint(createSecurityConstraint()); 
     }; 
    } 

    private LoginConfig createLoginConfig() { 
     LoginConfig config = new LoginConfig(); 
     config.setAuthMethod(LOGIN_CONFIG_AUTH_METHOD); 
     return config; 
    } 

    private SecurityConstraint createSecurityConstraint() { 
     SecurityConstraint securityConstraint = new SecurityConstraint(); 
     securityConstraint.setDisplayName("Employee certificate required"); 
     SecurityCollection securityCollection = new SecurityCollection("sec_collection"); 
     securityCollection.addPattern("/test/*"); 
     securityConstraint.addCollection(securityCollection); 
     securityConstraint.addAuthRole("new_role"); 
     securityConstraint.setAuthConstraint(true); 
     securityConstraint.setUserConstraint("CONFIDENTIAL"); 
     return securityConstraint; 
    } 

} 

application.properties mit neuem SSL-Anschluss Config

server.port=8443 

server.ssl.enabled=true 
server.ssl.client-auth=need 

server.ssl.key-store=classpath:certs/serverkeystore.p12 
server.ssl.key-store-password=changeit 
server.ssl.key-store-type=PKCS12 
server.ssl.key-alias=serverkey 

server.ssl.trust-store=classpath:certs/servertruststore.jks 
server.ssl.trust-store-password=changeit 
server.ssl.trust-store-type=jks 

Mit eigenständiger Tomcat und gleichen config in XML geschrieben kein zusätzlichen SSLAuthenticator Ventil benötigt wird.

Verwandte Themen