Skip to content
This repository has been archived by the owner on Aug 11, 2020. It is now read-only.

Commit

Permalink
NEXUS-4257, No longer creating a session for anonymous request. Also …
Browse files Browse the repository at this point in the history
…if you now set the header: "X-Nexus-Session: none" a session will NOT be created.

Cleaned up the test a bit, (changed to hamcrest asserts)
  • Loading branch information
bdemers authored and Richard Seddon committed Oct 27, 2011
1 parent db573b7 commit 11e4937
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 53 deletions.
Expand Up @@ -38,12 +38,15 @@
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonatype.nexus.security.filter.authc.NexusHttpAuthenticationFilter;

public class StatelessAndStatefulWebSessionManager
extends DefaultWebSessionManager
{
private static final Logger log = LoggerFactory.getLogger( DefaultWebSessionManager.class );

public static final String NO_SESSION_HEADER = "X-Nexus-Session";

private SessionIdGenerator fakeSessionIdGenerator = new JavaUuidSessionIdGenerator();

protected Session doCreateSession( SessionContext context )
Expand Down Expand Up @@ -177,6 +180,16 @@ private void storeSessionId( Serializable currentId, HttpServletRequest request,

protected boolean isStatelessClient( final ServletRequest request )
{
if( hasNoSessionHeader( request ) )
{
return true;
}

if( Boolean.TRUE.equals( request.getAttribute( NexusHttpAuthenticationFilter.ANONYMOUS_LOGIN ) ) )
{
return true;
}

final String userAgent = getUserAgent( request );

if ( userAgent != null && userAgent.trim().length() > 0 )
Expand Down Expand Up @@ -211,17 +224,74 @@ protected boolean isStatelessClient( final ServletRequest request )
return true;
}

// Nexus
if ( userAgent.startsWith( "Nexus/" ) )
{
return true;
}

// Artifactory
if ( userAgent.startsWith( "Artifactory/" ) )
{
return true;
}

// Apache Archiva
if ( userAgent.startsWith( "Apache Archiva/" ) )
{
return true;
}

// M2Eclipse
if ( userAgent.startsWith( "M2Eclipse/" ) )
{
return true;
}

// Aether
if ( userAgent.startsWith( "Aether/" ) )
{
return true;
}
}

// we can't decided for sure, let's return the safest
return false;
}

/**
* Checks for the no session header: "X-Nexus-Session: none".
* @param request
* @return true if header 'X-Nexus-Session' is 'none', false otherwise.
*/
private boolean hasNoSessionHeader( final ServletRequest request )
{
//"X-Nexus-Session: none"
return "none".equals( getHeaderValue( NO_SESSION_HEADER, request ) );
}

/**
* Returns the User-Agent of the request, or null if not set.
* @param request
* @return
*/
private String getUserAgent( final ServletRequest request )
{
return getHeaderValue( "User-Agent", request );
}

/**
* Gets a header value from the request if the ServletRequest is a HttpServletRequest.
*
* @param headerName
* @param request
* @return null if request is not HttpServletRequest, or header is not found.
*/
private String getHeaderValue( String headerName, final ServletRequest request )
{
if ( request instanceof HttpServletRequest )
{
final String userAgent = ( (HttpServletRequest) request ).getHeader( "User-Agent" );
final String userAgent = ( (HttpServletRequest) request ).getHeader( headerName );
return userAgent;
}
return null;
Expand Down
Expand Up @@ -19,6 +19,8 @@
package org.sonatype.nexus.integrationtests.nexus4257;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
Expand All @@ -32,11 +34,14 @@
import org.sonatype.nexus.integrationtests.TestContainer;
import org.sonatype.nexus.integrationtests.TestContext;
import org.sonatype.nexus.rest.model.GlobalConfigurationResource;
import org.sonatype.nexus.security.StatelessAndStatefulWebSessionManager;
import org.sonatype.nexus.test.utils.SettingsMessageUtil;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;


public class Nexus4257CookieVerificationIT
extends AbstractNexusIntegrationTest
Expand All @@ -48,114 +53,126 @@ public void setSecureTest()
TestContainer.getInstance().getTestContext().setSecureTest( true );
}

@Override
protected void runOnce()
throws Exception
{
// disable anonymous access
GlobalConfigurationResource settings = SettingsMessageUtil.getCurrentSettings();
settings.setSecurityAnonymousAccessEnabled( false );
SettingsMessageUtil.save( settings );

}

@Test
public void testCookieForStateFullClient()
throws HttpException, IOException
throws Exception
{
setAnonymousAccess( false );

TestContext context = TestContainer.getInstance().getTestContext();
String username = context.getAdminUsername();
String password = context.getPassword();
String url = this.getBaseNexusUrl() + "content/";

// default useragent is: Jakarta Commons-HttpClient/3.1[\r][\n]
HttpClient httpClient = new HttpClient();
HttpClient httpClient = new HttpClient();
httpClient.getState().setCredentials( AuthScope.ANY, new UsernamePasswordCredentials( username, password ) );

GetMethod getMethod = new GetMethod( url );
Assert.assertEquals( executeAndRelease( httpClient, getMethod ), 200 );
assertThat( executeAndRelease( httpClient, getMethod ), equalTo( 200 ) );
Cookie sessionCookie = this.getSessionCookie( httpClient.getState().getCookies() );
Assert.assertNotNull( sessionCookie, "Session Cookie not set" );
assertThat( "Session Cookie not set", sessionCookie, notNullValue() );
httpClient.getState().clear(); // remove cookies, credentials, etc

// do not set the cookie, expect failure
GetMethod failedGetMethod = new GetMethod( url );
Assert.assertEquals( executeAndRelease( httpClient, failedGetMethod ), 401 );
assertThat( executeAndRelease( httpClient, getMethod ), equalTo( 401 ) );

// set the cookie expect a 200, If a cookie is set, and cannot be found on the server, the response will fail with a 401
httpClient.getState().addCookie( sessionCookie );
getMethod = new GetMethod( url );
Assert.assertEquals( executeAndRelease( httpClient, getMethod ), 200 );
assertThat( executeAndRelease( httpClient, getMethod ), equalTo( 200 ) );
}


/**
* Tests that session cookies are not set for the list of known stateless clients.
* @throws Exception
*/
@Test
public void testCookieForStateLessClient()
throws HttpException, IOException
throws Exception
{
setAnonymousAccess( false );

String[] statelessUserAgents = {
"Java",
"Apache-Maven",
"Apache Ivy",
"curl",
"Wget",
"Nexus",
"Artifactory",
"Apache Archiva",
"M2Eclipse",
"Aether"
};

for( String userAgent : statelessUserAgents )
{
testCookieNotSetForKnownStateLessClients( userAgent );
}
}

/**
* Makes a request after setting the user agent and verifies that the session cookie is NOT set.
* @param userAgent
* @throws Exception
*/
private void testCookieNotSetForKnownStateLessClients( String userAgent ) throws Exception
{
TestContext context = TestContainer.getInstance().getTestContext();
String username = context.getAdminUsername();
String password = context.getPassword();
String url = this.getBaseNexusUrl() + "content/";

Header header = new Header("User-Agent", "Java/1.6" );

// default useragent is: Jakarta Commons-HttpClient/3.1[\r][\n]
HttpClient httpClient = new HttpClient();
Header header = new Header("User-Agent", userAgent + "/1.6" ); // user agent plus some version

HttpClient httpClient = new HttpClient();
httpClient.getState().setCredentials( AuthScope.ANY, new UsernamePasswordCredentials( username, password ) );

GetMethod getMethod = new GetMethod( url );
getMethod.addRequestHeader( header );
Assert.assertEquals( executeAndRelease( httpClient, getMethod ), 200 );
assertThat( executeAndRelease( httpClient, getMethod ), equalTo( 200 ) );

Cookie sessionCookie = this.getSessionCookie( httpClient.getState().getCookies() );
Assert.assertNull( sessionCookie, "Session Cookie is set" );
assertThat( "Session Cookie should not be set for user agent: " + userAgent, sessionCookie, nullValue() );
}


/**
* Tests that an anonymous user with a stateless client does NOT receive a session cookie.
* @throws HttpException
* @throws IOException
*/
@Test
public void testCookieForStateFullClientForAnonUser()
throws HttpException, IOException
throws Exception
{
setAnonymousAccess( true );

GlobalConfigurationResource settings = SettingsMessageUtil.getCurrentSettings();
settings.setSecurityAnonymousAccessEnabled( true );
SettingsMessageUtil.save( settings );

TestContext context = TestContainer.getInstance().getTestContext();
String username = context.getAdminUsername();
String password = context.getPassword();
String url = this.getBaseNexusUrl() + "content/";

// default useragent is: Jakarta Commons-HttpClient/3.1[\r][\n]
HttpClient httpClient = new HttpClient(); // anonymous access

GetMethod getMethod = new GetMethod( url );
Assert.assertEquals( executeAndRelease( httpClient, getMethod ), 200 );
assertThat( executeAndRelease( httpClient, getMethod ), equalTo( 200 ) );

Cookie sessionCookie = this.getSessionCookie( httpClient.getState().getCookies() );
Assert.assertNotNull( sessionCookie, "Session Cookie not set" );

httpClient.getState().clear(); // remove cookies, credentials, etc
// set the cookie expect a 200, If a cookie is set, and cannot be found on the server, the response will fail with a 401
httpClient.getState().addCookie( sessionCookie );
getMethod = new GetMethod( url );
Assert.assertEquals( executeAndRelease( httpClient, getMethod ), 200 );
assertThat( "Session Cookie should not be set", sessionCookie, nullValue() );
}


/**
* Tests that an anonymous user with a stateless client does NOT receive a session cookie.
* @throws HttpException
* @throws IOException
*/
@Test
public void testCookieForStateLessClientForAnonUser()
throws HttpException, IOException
throws Exception
{
GlobalConfigurationResource settings = SettingsMessageUtil.getCurrentSettings();
settings.setSecurityAnonymousAccessEnabled( true );
SettingsMessageUtil.save( settings );
setAnonymousAccess( true );

TestContext context = TestContainer.getInstance().getTestContext();
String username = context.getAdminUsername();
String password = context.getPassword();
String url = this.getBaseNexusUrl() + "content/";

Header header = new Header("User-Agent", "Java/1.6" );
Expand All @@ -165,10 +182,40 @@ public void testCookieForStateLessClientForAnonUser()

GetMethod getMethod = new GetMethod( url );
getMethod.addRequestHeader( header );
Assert.assertEquals( executeAndRelease( httpClient, getMethod ), 200 );
assertThat( executeAndRelease( httpClient, getMethod ), equalTo( 200 ) );

Cookie sessionCookie = this.getSessionCookie( httpClient.getState().getCookies() );
assertThat( "Session Cookie should not be set", sessionCookie, nullValue() );
}

/**
* Verifies that requests with the header: X-Nexus-Session do not have session cookies set.
* @throws Exception
*/
@Test
public void testNoSessionHeader() throws Exception
{
setAnonymousAccess( true );

String url = this.getBaseNexusUrl() + "content/";

// default useragent is: Jakarta Commons-HttpClient/3.1[\r][\n]
HttpClient httpClient = new HttpClient(); // anonymous access

Header header = new Header( StatelessAndStatefulWebSessionManager.NO_SESSION_HEADER, "none" );

GetMethod getMethod = new GetMethod( url );
assertThat( executeAndRelease( httpClient, getMethod ), equalTo( 200 ) );

Cookie sessionCookie = this.getSessionCookie( httpClient.getState().getCookies() );
Assert.assertNull( sessionCookie, "Session Cookie is set" );
assertThat( "Session Cookie should not be set", sessionCookie, nullValue() );
}

private void setAnonymousAccess( boolean enabled ) throws Exception
{
GlobalConfigurationResource settings = SettingsMessageUtil.getCurrentSettings();
settings.setSecurityAnonymousAccessEnabled( enabled );
SettingsMessageUtil.save( settings );
}

private Cookie getSessionCookie( Cookie[] cookies )
Expand Down Expand Up @@ -200,4 +247,5 @@ private int executeAndRelease( HttpClient httpClient, HttpMethodBase method )

return status;
}

}

0 comments on commit 11e4937

Please sign in to comment.