/*
 * Copyright 2014 Apereo Foundation (AF) Licensed under the
 * Educational Community License, Version 2.0 (the 'License'); you may
 * not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 *
 *     http://opensource.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an 'AS IS'
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

var _ = require('underscore');
var assert = require('assert');
var fs = require('fs');

var OaeServer = require('oae-util/lib/server');
var PrincipalsTestUtil = require('oae-principals/lib/test/util');
var RestAPI = require('oae-rest');
var RestUtil = require('oae-rest/lib/util');
var TestsUtil = require('oae-tests');

describe('OAE Server', function() {

    // Rest context for the cam admin
    var camAdminRestContext = null;

    /*!
     * Function that will set up the user contexts
     */
    before(function(callback) {
        // Fill up Cam tenant admin rest context
        camAdminRestContext = TestsUtil.createTenantAdminRestContext(global.oaeTests.tenants.cam.host);
        callback();
    });

    describe('CSRF', function() {

        /*!
         * Verifies CSRF validation with invalid hosts and safe paths
         */
        it('verify CSRF validation with invalid hosts and safe paths', function(callback) {
            TestsUtil.generateTestUsers(camAdminRestContext, 1, function(err, user) {
                assert.ok(!err);
                user = user[_.keys(user)[0]];

                // Ensure we can authenticate
                RestAPI.User.getMe(user.restContext, function(err, me) {
                    assert.ok(!err);
                    assert.equal(user.user.id, me.id);

                    // Sanity check we can sign out
                    RestAPI.Authentication.logout(user.restContext, function(err) {
                        assert.ok(!err);

                        // Verify we are anonymous
                        RestAPI.User.getMe(user.restContext, function(err, me) {
                            assert.ok(!err);
                            assert.ok(!me.id);
                            assert.ok(me.anon);

                            // Spoof the referer to be a relative uri. This should pass CSRF validation
                            user.restContext.refererHeader = '/some/path';

                            // Log back in
                            RestAPI.Authentication.login(user.restContext, user.restContext.username, user.restContext.userPassword, function(err) {
                                assert.ok(!err);

                                // Verify we are authenticated
                                RestAPI.User.getMe(user.restContext, function(err, me) {
                                    assert.ok(!err);
                                    assert.equal(user.user.id, me.id);

                                    // Spoof the referer
                                    user.restContext.refererHeader = 'http://www.google.com';

                                    // Verify CSRF validation catches this request
                                    RestAPI.Authentication.logout(user.restContext, function(err, data) {
                                        assert.ok(err);
                                        assert.equal(err.code, 500);
                                        assert.strictEqual(err.msg.indexOf('CSRF'), 0);

                                        // Spoof the referer to be empty
                                        user.restContext.refererHeader = '';

                                        // Verify CSRF validation says no dice
                                        RestAPI.Authentication.logout(user.restContext, function(err, data) {
                                            assert.ok(err);
                                            assert.equal(err.code, 500);
                                            assert.strictEqual(err.msg.indexOf('CSRF'), 0);

                                            // Verify we are still authenticated (this is a GET request, CSRF validation will not happen here with our spoofed referer)
                                            RestAPI.User.getMe(user.restContext, function(err, me) {
                                                assert.ok(!err);
                                                assert.equal(user.user.id, me.id);

                                                // Make the logout API path safe from CSRF validation
                                                OaeServer.addSafePathPrefix('/api/auth/logout');

                                                // Sanity check we can now sign out, even with an invalid referer
                                                RestAPI.Authentication.logout(user.restContext, function(err) {
                                                    assert.ok(!err);

                                                    // Verify we are now anonymous
                                                    RestAPI.User.getMe(user.restContext, function(err, me) {
                                                        assert.ok(!err);
                                                        assert.ok(!me.id);
                                                        assert.ok(me.anon);
                                                        callback();
                                                    });
                                                });
                                            });
                                        });
                                    });
                                });
                            });
                        });
                    });
                });
            });
        });
    });

    describe('Multipart Uploads', function() {

        /**
         * Utility method that returns a file stream
         *
         * @return {Stream}     A file stream
         */
        var getFileStream = function() {
            return fs.createReadStream(__dirname + '/data/banditos.txt');
        };

        /**
         * Test that verifies multiple files can be uploaded in the same request parameter
         */
        it('verify multiple files can be uploaded in the same request parameter', function(callback) {
            TestsUtil.createTestServer(function(app, server, port) {

                app.post('/testUploadFiles', function(request, response) {
                    assert.ok(_.isArray(request.files.testFiles));
                    assert.strictEqual(request.files.testFiles.length, 2);
                    assert.equal(request.files.testFiles[0].name, 'banditos.txt');
                    assert.equal(request.files.testFiles[1].name, 'banditos.txt');

                    response.send(200);
                    server.close(callback);
                });

                var opts = {'method': 'POST', 'url': 'http://localhost:' + port + '/testUploadFiles'};
                RestUtil.request(opts, {'testFiles': [getFileStream, getFileStream]});
            });
        });
    });

    describe('Cookies', function() {

        /**
         * Verify that a fixed cookie name is used
         */
        it('verify a fixed cookie name is used', function(callback) {
            TestsUtil.generateTestUsers(camAdminRestContext, 1, function(err, user, simong) {
                assert.ok(!err);

                // Ensure the user is authenticated
                PrincipalsTestUtil.assertGetMeSucceeds(simong.restContext, function(me) {
                    assert.ok(!me.anon)

                    // Get the cookies from the cookie har
                    var cookies = simong.restContext.cookieJar.getCookies('http://localhost');
                    var cookieNames = _.pluck(cookies, 'key');

                    // Verify the configured cookie names are being used
                    var config = require('../../../config.js').config;
                    assert.ok(_.contains(cookieNames, config.cookie.name));

                    // Remove the session cookie from the jar
                    delete simong.restContext.cookieJar._jar.store.idx.localhost['/'][config.cookie.name];

                    // Ensure the user is anonymous
                    PrincipalsTestUtil.assertGetMeSucceeds(simong.restContext, function(me) {
                        assert.strictEqual(me.anon, true)

                        return callback();
                    });
                });
            });
        });
    });
});

@@ -8282,150 +8282,268 @@
 / Re
-mov
+nam
 e the 
-session cookie from the jar%0A                    delete simong.restContext.cookieJar._jar.store.idx.localhost%5B'/'%5D%5Bconfig.cookie.name%5D
+cookie to something else%0A                    _.each(cookies, function(cookie) %7B%0A                        if (cookie.key === config.cookie.name) %7B%0A                            cookie.key = 'somethingElse';%0A                        %7D%0A                    %7D)
 ;%0A%0A 

Rename the cookie rather then deleting to test for a fixed name