Skip to content

Commit

Permalink
Finished authentication; added unit tests to include the Examples pag…
Browse files Browse the repository at this point in the history
…es to check for 200 status
  • Loading branch information
marcesher committed Jan 10, 2011
1 parent d3204a7 commit 126b715
Show file tree
Hide file tree
Showing 4 changed files with 612 additions and 534 deletions.
65 changes: 46 additions & 19 deletions core/Mongo.cfc
Expand Up @@ -38,15 +38,20 @@
mongoUtil = new MongoUtil(mongoFactory);

// Check for authentication, and if we have details set call it once on this database instance
if ( len(mongoConfig.getAuthDetails().username) and not authenticate(mongoConfig.getAuthDetails().username, mongoConfig.getAuthDetails().password) ) {
throw( message="Error authenticating MongoDB database." );
if ( len(mongoConfig.getAuthDetails().username) and isAuthenticationRequired() ) {
var authResult = authenticate(mongoConfig.getAuthDetails().username, mongoConfig.getAuthDetails().password);
if( structIsEmpty(authResult.error) ) {
throw( message="Error authenticating against MongoDB Database", type="AuthenticationFailedException" );
} else {
throw(object=authResult.error);
}
}

return this;
}

/**
* authenticates connection/db with given name and password
* Authenticates connection/db with given name and password
Typical usage:
mongoConfig.init(...);
Expand All @@ -57,24 +62,45 @@
If authentication fails, an error will be thrown
*
*/
boolean function authenticate( string username, string password ){
return getMongoDB( variables.mongoConfig ).authenticate( arguments.username, arguments.password.toCharArray() );
struct function authenticate( string username, string password ){
var result = {authenticated = false, error={}};
try{
result.authenticated = getMongoDB( variables.mongoConfig ).authenticate( arguments.username, arguments.password.toCharArray() );
}
catch( any e ){
result.error = e;
}
return result;
}

/**
* Attempts to determine whether mongod is running in auth mode
*/
boolean function isAuthenticationRequired(){
try{
getIndexes("foo");
return false;
}catch(any e){
return true;
}
}
/* adds a user to the database
*

/**
* Adds a user to the database
*/
void function addUser( string username, string password) {
function addUser( string username, string password) {
getMongoDB( variables.mongoConfig ).addUser(arguments.username, arguments.password.toCharArray());
return this;
}
/* drops the database
*

/**
* Drops the database currently specified in MongoConfig
*/
void function dropDatabase() {
function dropDatabase() {
variables.mongo.dropDatabase(variables.mongoConfig.getDBName());
return this;
}


/**
* Closes the underlying mongodb object. Once closed, you cannot perform additional mongo operations and you'll need to init a new mongo.
Expand All @@ -94,6 +120,7 @@
//the error that this throws *appears* to be harmless.
writeLog("Error closing Mongo: " & e.message);
}
return this;
}

/**
Expand Down Expand Up @@ -379,7 +406,7 @@


/**
* the array of fields can either be
* The array of fields can either be
a) an array of field names. The sort direction will be "1"
b) an array of structs in the form of fieldname=direction. Eg:
Expand Down Expand Up @@ -414,9 +441,7 @@
}

/**
* ensures a "2d" index on a single field. If another 2d index exists on the same collection, this will error
* Ensures a "2d" index on a single field. If another 2d index exists on the same collection, this will error
*/
public array function ensureGeoIndex(field, collectionName, min="", max="", mongoConfig=""){
var collection = getMongoDBCollection(collectionName, mongoConfig);
Expand Down Expand Up @@ -448,7 +473,9 @@
return getIndexes( collectionName, mongoConfig );
}

//decide whether to use the one in the variables scope, the one being passed around as arguments, or create a new one
/**
* Decide whether to use the MongoConfig in the variables scope, the one being passed around as arguments, or create a new one
*/
function getMongoConfig(mongoConfig=""){
if(isSimpleValue(arguments.mongoConfig)){
mongoConfig = variables.mongoConfig;
Expand Down
104 changes: 54 additions & 50 deletions test/AuthenticationTest.cfc
@@ -1,72 +1,76 @@
<!---
*************************************************************************************
************************************ COMMENTS ***************************************
*************************************************************************************
Name: AuthenticationTest.cfc
Author: Ciarán Archer
Date: 27 December 2010
Params:
<!---
Original Author: Ciarán Archer
Desc: Set of MXUnit tests to verify Mongo.cfc authentication functionality
works.
Note: presumes that mongod was started with --auth.
More info here: http://www.mongodb.org/display/DOCS/Security+and+Authentication
works.
*************************************************************************************
*************************************************************************************
ADJUSTMENTS:
Note: presumes that mongod was started with --auth, BUT we don't run tests against an authenticated mongod. Consequently,
we have to mock these behaviors and test that *our* code responds against what we currently know to be MongoDB's behavior
when running a DB in auth mode
If you run these tests with --auth, they will no doubt fail
More info here: http://www.mongodb.org/display/DOCS/Security+and+Authentication
*************************************************************************************
--->

<!---
WHERE I AM with these tests
1) need to add a user to admin.system.users or do whatever it takes to see what actually happens when an authenticated attempt fails due to not being authed
2) spoof the query() function to throw a similar error
3) have mongo.init() check for authentication required and work that into authenticate()
4) get these tests testing that behavior.
NOTE: to get this working:
use admin
db.addUser("one","one")
then attempted to query against it
--->

<cfcomponent output="false" extends="mxunit.framework.TestCase">
<cfscript>
import cfmongodb.core.*;

variables.testDatabase = "cfmongodb_test_auth";
variables.testCollection = "myTestCollection";
variables.testDatabase = "cfmongodb_auth_tests";
variables.testCollection = "authtests";
variables.javaloaderFactory = createObject('component','cfmongodb.core.JavaloaderFactory').init();
variables.mongoConfig = createObject('component','cfmongodb.core.MongoConfig').init(dbName=variables.testDatabase, mongoFactory=javaloaderFactory);


function setUp() {

// create cfmongodb instance
variables.mongo = createObject('component','cfmongodb.core.Mongo').init(mongoConfig);

}
variables.mongoConfig.setAuthDetails("username", "verysecurepassword!");

function testSaveWithoutCredentials() {
function init_should_error_when_authentication_fails() {
expectException("AuthenticationFailedException");

// TODO: attempt to save a document without authenticating
assertEquals(1, 1);

}
var mongo = createObject('component','cfmongodb.core.Mongo');
//we entirely spoof the authentication internals
injectMethod(mongo, this, "isAuthenticationRequiredOverride", "isAuthenticationRequired");
injectMethod(mongo, this, "authenticateOverride", "authenticate");

mongo.init(mongoConfig);
}

function testSaveWithCredentials() {

// TODO: attempt to save a document after authenticating
assertEquals(1, 1);

}
function tearDown(){

var mongo = createObject('component','cfmongodb.core.Mongo').init(mongoConfig);
try{
mongo.dropDatabase();
}catch(any e){
debug("error dropping database");
debug(e);
}

//close connection
mongo.close();

function tearDown(){
}

// remove database
variables.mongo.dropDatabase();

//close connection
variables.mongo.close();

}
private function isAuthenticationRequiredOverride(){ return true; }
private function authenticateOverride(){ return {authenticated=false, error={}}; }


</cfscript>
Expand Down
29 changes: 29 additions & 0 deletions test/IncludeExamplesTest.cfc
@@ -0,0 +1,29 @@
<cfcomponent extends="mxunit.framework.TestCase">

<cffunction name="setUp" returntype="void" access="public" hint="put things here that you want to run before each test">
<cfset variables.rootURL = "http://" & cgi.SERVER_NAME & ":" & cgi.SERVER_PORT & "/cfmongodb/examples/">
<cfset debug(cgi)>

<cfset paths = ["gettingstarted.cfm", "aggregation/group.cfm", "aggregation/mapReduce.cfm", "geospatial/geo.cfm", "PeopleList/index.cfm"]>

</cffunction>


<cffunction name="all_examples_should_work" returntype="void" access="public">
<cfset var httpResult = "">
<cfset var path = "">
<cfset var currentURL = "">
<cfloop array="#paths#" index="path">
<cfset currentURL = variables.rootURL & path>
<cfhttp method="get" url="#currentURL#" result="httpResult">
<cfif httpResult.statusCode neq "200 OK">

<cfset debug(httpResult.fileContent)>
<cfset fail("For #currentURL#, path Expected 200 OK but received #httpResult.statusCode#.")>

</cfif>
</cfloop>

</cffunction>

</cfcomponent>

0 comments on commit 126b715

Please sign in to comment.