Skip to content

Commit

Permalink
roboconf#632 User authentication (WTF)
Browse files Browse the repository at this point in the history
  • Loading branch information
vincent-zurczak committed Apr 6, 2017
1 parent 8d04c81 commit 179b79b
Show file tree
Hide file tree
Showing 22 changed files with 627 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ public interface UrlConstants {
String PREFERENCES = "preferences";
String SCHEDULER = "scheduler";
String AUTHENTICATION = "auth";

String SESSION_ID = "sid";
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ public class AuthenticationManager {
private IAuthService authService;


/**
* @author Vincent Zurczak - Linagora
*/
public static enum REST_ROLES {
ADM, TPL_RW, APP_RW, APP_R
}



/**
* Constructor.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public void starting() throws Exception {
this.app.setScheduler( this.scheduler );
this.app.setMavenResolver( this.mavenResolver );
this.app.enableCors( this.enableCors );
this.app.setAuthenticationManager( this.authenticationMngr );

Dictionary<String,String> initParams = new Hashtable<> ();
initParams.put( "servlet-name", "Roboconf DM (REST)" );
Expand All @@ -135,12 +136,17 @@ public void starting() throws Exception {
// Register a filter for authentication
this.authenticationFilter = new AuthenticationFilter();
this.authenticationFilter.setAuthenticationEnabled( this.enableAuthentication );
this.authenticationFilter.setAuthenticationMngr( this.authenticationMngr );
this.authenticationFilter.setAuthenticationManager( this.authenticationMngr );
this.authenticationFilter.setSessionPeriod( this.sessionPeriod );

initParams = new Hashtable<> ();
initParams.put( "urlPatterns", "*" );
this.filterServiceRegistration = this.bundleContext.registerService( Filter.class, this.authenticationFilter, initParams );

// Consider the bundle context can be null (e.g. when used outside of OSGi)
if( this.bundleContext != null )
this.filterServiceRegistration = this.bundleContext.registerService( Filter.class, this.authenticationFilter, initParams );
else
this.logger.warning( "No bundle context was available, the authentication filter was not registered." );
}


Expand Down Expand Up @@ -289,7 +295,7 @@ public void setAuthenticationRealm( String authenticationRealm ) {

// Propagate the change
if( this.authenticationFilter != null )
this.authenticationFilter.setAuthenticationMngr( this.authenticationMngr );
this.authenticationFilter.setAuthenticationManager( this.authenticationMngr );

if( this.app != null )
this.app.setAuthenticationManager( this.authenticationMngr );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import javax.servlet.http.HttpServletResponse;

import net.roboconf.core.utils.Utils;
import net.roboconf.dm.rest.commons.UrlConstants;
import net.roboconf.dm.rest.commons.security.AuthenticationManager;
import net.roboconf.dm.rest.services.internal.resources.IAuthenticationResource;

Expand All @@ -55,7 +56,6 @@
*/
public class AuthenticationFilter implements Filter {

public static final String SESSION_ID = "sid";
private final Logger logger = Logger.getLogger( getClass().getName());

private AuthenticationManager authenticationMngr;
Expand All @@ -81,7 +81,7 @@ public void doFilter( ServletRequest req, ServletResponse resp, FilterChain chai
Cookie[] cookies = request.getCookies();
if( cookies != null ) {
for( Cookie cookie : cookies ) {
if( SESSION_ID.equals( cookie.getName())) {
if( UrlConstants.SESSION_ID.equals( cookie.getName())) {
sessionId = cookie.getValue();
break;
}
Expand All @@ -99,7 +99,7 @@ public void doFilter( ServletRequest req, ServletResponse resp, FilterChain chai

// Valid session, go on. Send an error otherwise.
// No redirection, we mainly deal with our web socket and REST API.
boolean loginRequest = IAuthenticationResource.LOGIN_PATH.equals( requestedPath );
boolean loginRequest = requestedPath.endsWith( IAuthenticationResource.PATH + IAuthenticationResource.LOGIN_PATH );
if( loggedIn || loginRequest ) {
chain.doFilter( request, response );
} else {
Expand Down Expand Up @@ -132,7 +132,7 @@ public void setAuthenticationEnabled( boolean authenticationEnabled ) {
/**
* @param authenticationMngr the authenticationMngr to set
*/
public void setAuthenticationMngr( AuthenticationManager authenticationMngr ) {
public void setAuthenticationManager( AuthenticationManager authenticationMngr ) {
this.authenticationMngr = authenticationMngr;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
public interface IAuthenticationResource {

String PATH = "/" + UrlConstants.AUTHENTICATION;
String LOGIN_PATH = PATH + "/e";
String LOGIN_PATH = "/e";


/**
Expand All @@ -67,5 +67,5 @@ public interface IAuthenticationResource {
*/
@POST
@Path("/s")
Response logout( @CookieParam( AuthenticationFilter.SESSION_ID ) String sessionId );
Response logout( @CookieParam( UrlConstants.SESSION_ID ) String sessionId );
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import net.roboconf.dm.rest.commons.UrlConstants;
import net.roboconf.dm.rest.commons.security.AuthenticationManager;
import net.roboconf.dm.rest.services.internal.filters.AuthenticationFilter;
import net.roboconf.dm.rest.services.internal.resources.IAuthenticationResource;

/**
Expand All @@ -52,12 +52,18 @@ public Response login( String username, String password ) {

String sessionId;
Response response;
if( this.authenticationManager == null )
if( this.authenticationManager == null ) {
response = Response.status( Status.INTERNAL_SERVER_ERROR ).entity( "No authentication manager was available." ).build();
else if(( sessionId = this.authenticationManager.login( username, password )) == null )
this.logger.fine( "No authentication manager was available. User was " + username );

} else if(( sessionId = this.authenticationManager.login( username, password )) == null ) {
response = Response.status( Status.FORBIDDEN ).entity( "Authentication failed." ).build();
else
response = Response.ok().cookie( new NewCookie( AuthenticationFilter.SESSION_ID, sessionId )).build();
this.logger.fine( "Authentication failed. User was " + username );

} else {
response = Response.ok().cookie( new NewCookie( UrlConstants.SESSION_ID, sessionId )).build();
this.logger.fine( "Authentication succeeded. User was " + username );
}

// NewCookie's implementation uses NewCookie.DEFAULT_MAX_AGE as the default
// validity for a cookie, which means it is valid until the browser is closed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ public void testSetAuthenticationRealm() throws Exception {
this.register.authenticationFilter = Mockito.mock( AuthenticationFilter.class );

this.register.setAuthenticationRealm( "realm2" );
Mockito.verify( this.register.authenticationFilter, Mockito.only()).setAuthenticationMngr( Mockito.any( AuthenticationManager.class ));
Mockito.verify( this.register.authenticationFilter, Mockito.only()).setAuthenticationManager( Mockito.any( AuthenticationManager.class ));

// Stop...
this.register.stopping();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.junit.Test;
import org.mockito.Mockito;

import net.roboconf.dm.rest.commons.UrlConstants;
import net.roboconf.dm.rest.commons.security.AuthenticationManager;
import net.roboconf.dm.rest.services.internal.resources.IAuthenticationResource;

Expand Down Expand Up @@ -76,6 +77,7 @@ public void testDoFiler_withAuthentication_noCookie() throws Exception {
filter.setAuthenticationEnabled( true );

HttpServletRequest req = Mockito.mock( HttpServletRequest.class );
Mockito.when( req.getRequestURI()).thenReturn( "/whatever" );
HttpServletResponse resp = Mockito.mock( HttpServletResponse.class );
FilterChain chain = Mockito.mock( FilterChain.class );

Expand All @@ -101,14 +103,15 @@ public void testDoFiler_withAuthentication_withCookie_loggedIn() throws Exceptio

AuthenticationManager authMngr = Mockito.mock( AuthenticationManager.class );
Mockito.when( authMngr.isSessionValid( sessionId, sessionPeriod )).thenReturn( true );
filter.setAuthenticationMngr( authMngr );
filter.setAuthenticationManager( authMngr );

FilterChain chain = Mockito.mock( FilterChain.class );
HttpServletResponse resp = Mockito.mock( HttpServletResponse.class );
HttpServletRequest req = Mockito.mock( HttpServletRequest.class );
Mockito.when( req.getRequestURI()).thenReturn( "/whatever" );
Mockito.when( req.getCookies()).thenReturn( new Cookie[] {
new Cookie( "as", "as" ),
new Cookie( AuthenticationFilter.SESSION_ID, sessionId )
new Cookie( UrlConstants.SESSION_ID, sessionId )
});

filter.doFilter( req, resp, chain );
Expand All @@ -134,14 +137,15 @@ public void testDoFiler_withAuthentication_withCookie_notLoggedIn() throws Excep

AuthenticationManager authMngr = Mockito.mock( AuthenticationManager.class );
Mockito.when( authMngr.isSessionValid( sessionId, sessionPeriod )).thenReturn( false );
filter.setAuthenticationMngr( authMngr );
filter.setAuthenticationManager( authMngr );

FilterChain chain = Mockito.mock( FilterChain.class );
HttpServletResponse resp = Mockito.mock( HttpServletResponse.class );
HttpServletRequest req = Mockito.mock( HttpServletRequest.class );
Mockito.when( req.getRequestURI()).thenReturn( "/whatever" );
Mockito.when( req.getCookies()).thenReturn( new Cookie[] {
new Cookie( "as", "as" ),
new Cookie( AuthenticationFilter.SESSION_ID, sessionId )
new Cookie( UrlConstants.SESSION_ID, sessionId )
});

filter.doFilter( req, resp, chain );
Expand All @@ -162,7 +166,7 @@ public void testDoFiler_withAuthentication_noCookie_butLoginPageRequested() thro
filter.setAuthenticationEnabled( true );

HttpServletRequest req = Mockito.mock( HttpServletRequest.class );
Mockito.when( req.getRequestURI()).thenReturn( IAuthenticationResource.LOGIN_PATH );
Mockito.when( req.getRequestURI()).thenReturn( IAuthenticationResource.PATH + IAuthenticationResource.LOGIN_PATH );
Mockito.when( req.getCookies()).thenReturn( new Cookie[ 0 ]);

HttpServletResponse resp = Mockito.mock( HttpServletResponse.class );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
import org.junit.Test;
import org.mockito.Mockito;

import net.roboconf.dm.rest.commons.UrlConstants;
import net.roboconf.dm.rest.commons.security.AuthenticationManager;
import net.roboconf.dm.rest.commons.security.AuthenticationManager.IAuthService;
import net.roboconf.dm.rest.services.internal.filters.AuthenticationFilter;

/**
* @author Vincent Zurczak - Linagora
Expand Down Expand Up @@ -68,7 +68,7 @@ public void testLoginAndLogout() throws Exception {

NewCookie cookie = (NewCookie) resp.getMetadata().getFirst( "Set-Cookie" );
Assert.assertNotNull( cookie );
Assert.assertEquals( AuthenticationFilter.SESSION_ID, cookie.getName());
Assert.assertEquals( UrlConstants.SESSION_ID, cookie.getName());
Assert.assertNotNull( cookie.getValue());
Assert.assertTrue( authMngr.isSessionValid( cookie.getValue(), -1 ));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ log4j.appender.jersey.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-32.32c{1
log4j.appender.jersey.file=${karaf.data}/log/jersey.log
log4j.appender.jersey.append=true

# Silent very verbose loggers but let them associated with the "roboconf" appender
# Silent very verbose loggers but let them associated with various appenders
log4j.logger.net.roboconf.dm.internal.tasks.CheckerForStoredMessagesTask=DEBUG, roboconf
log4j.logger.net.roboconf.dm.internal.tasks.CheckerForTargetsConfigurationTask=DEBUG, roboconf
log4j.logger.net.roboconf.dm.internal.tasks.CheckerForHeartbeatsTask=DEBUG, roboconf
log4j.logger.net.roboconf.dm.rest.services.internal.resources.impl.ApplicationResource=DEBUG, roboconf
log4j.logger.net.roboconf.target.api.AbstractThreadedTargetHandler$CheckingRunnable=DEBUG, roboconf
log4j.logger.net.roboconf.dm.internal.environment.messaging.DmMessageProcessor=DEBUG, roboconf
log4j.org.apache.karaf.jaas.modules.audit.LogAuditLoginModule=WARN, karaf
log4j.logger.org.apache.karaf.jaas.modules.audit.LogAuditLoginModule=WARN, karaf
6 changes: 6 additions & 0 deletions miscellaneous/roboconf-dm-rest-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@
<version>4.3.1</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,22 @@

package net.roboconf.dm.rest.client;

import javax.ws.rs.core.Cookie;

import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;

import net.roboconf.dm.rest.client.delegates.ApplicationWsDelegate;
import net.roboconf.dm.rest.client.delegates.AuthenticationWsDelegate;
import net.roboconf.dm.rest.client.delegates.DebugWsDelegate;
import net.roboconf.dm.rest.client.delegates.ManagementWsDelegate;
import net.roboconf.dm.rest.client.delegates.PreferencesWsDelegate;
import net.roboconf.dm.rest.client.delegates.SchedulerWsDelegate;
import net.roboconf.dm.rest.client.delegates.TargetWsDelegate;
import net.roboconf.dm.rest.commons.UrlConstants;
import net.roboconf.dm.rest.commons.json.ObjectMapperProvider;

/**
Expand Down Expand Up @@ -80,8 +84,10 @@ public class WsClient {
private final TargetWsDelegate targetWsDelegate;
private final SchedulerWsDelegate schedulerDelegate;
private final PreferencesWsDelegate preferencesWsDelegate;
private final AuthenticationWsDelegate authenticationWsDelegate;

private final Client client;
private String sessionId;


/**
Expand All @@ -98,12 +104,13 @@ public WsClient( String rootUrl ) {
this.client.setFollowRedirects( true );

WebResource resource = this.client.resource( rootUrl );
this.applicationDelegate = new ApplicationWsDelegate( resource );
this.managementDelegate = new ManagementWsDelegate( resource );
this.debugDelegate = new DebugWsDelegate( resource );
this.targetWsDelegate = new TargetWsDelegate( resource );
this.schedulerDelegate = new SchedulerWsDelegate( resource );
this.preferencesWsDelegate = new PreferencesWsDelegate( resource );
this.applicationDelegate = new ApplicationWsDelegate( resource, this );
this.managementDelegate = new ManagementWsDelegate( resource, this );
this.debugDelegate = new DebugWsDelegate( resource, this );
this.targetWsDelegate = new TargetWsDelegate( resource, this );
this.schedulerDelegate = new SchedulerWsDelegate( resource, this );
this.preferencesWsDelegate = new PreferencesWsDelegate( resource, this );
this.authenticationWsDelegate = new AuthenticationWsDelegate( resource, this );
}


Expand Down Expand Up @@ -157,10 +164,48 @@ public PreferencesWsDelegate getPreferencesWsDelegate() {
return this.preferencesWsDelegate;
}

/**
* @return the authenticationWsDelegate
*/
public AuthenticationWsDelegate getAuthenticationWsDelegate() {
return this.authenticationWsDelegate;
}

/**
* @return the Jersey client (useful to configure it)
*/
public Client getJerseyClient() {
return this.client;
}

/**
* Sets the session ID to use when authenticated.
* @param sessionId
*/
public void setSessionId( String sessionId ) {
this.sessionId = sessionId;
}

/**
* @return the sessionId
*/
public String getSessionId() {
return this.sessionId;
}


/**
* @param resource a web resource
* @return a builder with an optional cookie (for authentication)
*/
public WebResource.Builder createBuilder( WebResource resource ) {

WebResource.Builder result;
if( this.sessionId != null )
result = resource.cookie( new Cookie( UrlConstants.SESSION_ID, this.sessionId ));
else
result = resource.getRequestBuilder();

return result;
}
}
Loading

0 comments on commit 179b79b

Please sign in to comment.