NOTICKET: Refactor with sessions. Now holds auth on server

Signed-off-by: KIRAN KASHALKAR <kiran.kashalkar@riftio.com>
diff --git a/skyquake/framework/core/api_utils/constants.js b/skyquake/framework/core/api_utils/constants.js
index 0aac7d2..7f54797 100644
--- a/skyquake/framework/core/api_utils/constants.js
+++ b/skyquake/framework/core/api_utils/constants.js
@@ -73,6 +73,7 @@
 constants.SOCKET_POOL_LENGTH = 20;
 constants.SERVER_PORT = process.env.SERVER_PORT || 8000;
 constants.SECURE_SERVER_PORT = process.env.SECURE_SERVER_PORT || 8443;
+constants.REJECT_UNAUTHORIZED = false;
 
 constants.BASE_PACKAGE_UPLOAD_DESTINATION = 'upload/packages/';
 constants.PACKAGE_MANAGER_SERVER_PORT = 4567;
diff --git a/skyquake/framework/core/api_utils/sockets.js b/skyquake/framework/core/api_utils/sockets.js
index 5e0b25b..0cd4918 100644
--- a/skyquake/framework/core/api_utils/sockets.js
+++ b/skyquake/framework/core/api_utils/sockets.js
@@ -33,6 +33,7 @@
 var sockjs = require('sockjs');
 var websocket_multiplex = require('websocket-multiplex');
 var utils = require('./utils.js');
+var configurationAPI = require('../modules/api/configuration.js');
 
 
 var Subscriptions = function() {
@@ -278,7 +279,7 @@
   self.isClosed = false;
   var requestHeaders = {};
   _.extend(requestHeaders, {
-    'Authorization': req.get('Authorization')
+    Cookie: req.get('Cookie')
   });
 
   var pollServer = function() {
diff --git a/skyquake/framework/core/api_utils/utils.js b/skyquake/framework/core/api_utils/utils.js
index 5b17279..68775f8 100644
--- a/skyquake/framework/core/api_utils/utils.js
+++ b/skyquake/framework/core/api_utils/utils.js
@@ -95,7 +95,7 @@
 
 var checkAuthorizationHeader = function(req) {
 	return new Promise(function(resolve, reject) {
-		if (req.get('Authorization') == null) {
+		if (req.session && req.session.authorization == null) {
 			reject();
 		} else {
 			resolve();
@@ -200,7 +200,7 @@
 				uri: uri,
 				method: 'GET',
 				headers: _.extend({}, CONSTANTS.HTTP_HEADERS.accept[type], {
-					'Authorization': req.get('Authorization'),
+					'Authorization': req.session && req.session.authorization,
 					forever: CONSTANTS.FOREVER_ON,
 					rejectUnauthorized: false,
 				})
diff --git a/skyquake/framework/core/modules/api/descriptorModelMetaAPI.js b/skyquake/framework/core/modules/api/descriptorModelMetaAPI.js
index b0223b2..34d30b3 100644
--- a/skyquake/framework/core/modules/api/descriptorModelMetaAPI.js
+++ b/skyquake/framework/core/modules/api/descriptorModelMetaAPI.js
@@ -36,7 +36,7 @@
                 uri: utils.confdPort(api_server) + '/api/schema/nsd-catalog/nsd',
                 method: 'GET',
                 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
-                    'Authorization': req.get('Authorization')
+                    'Authorization': req.session && req.session.authorization
                 }),
                 forever: constants.FOREVER_ON,
                 rejectUnauthorized: false,
@@ -46,7 +46,7 @@
                 uri: utils.confdPort(api_server) + '/api/schema/vnfd-catalog/vnfd',
                 method: 'GET',
                 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
-                    'Authorization': req.get('Authorization')
+                    'Authorization': req.session && req.session.authorization
                 }),
                 forever: constants.FOREVER_ON,
                 rejectUnauthorized: false,
diff --git a/skyquake/framework/core/modules/api/projectManagementAPI.js b/skyquake/framework/core/modules/api/projectManagementAPI.js
index d73eb21..8eace6b 100644
--- a/skyquake/framework/core/modules/api/projectManagementAPI.js
+++ b/skyquake/framework/core/modules/api/projectManagementAPI.js
@@ -36,7 +36,7 @@
                 uri: utils.confdPort(api_server) + '/api/operational/project',
                 method: 'GET',
                 headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
-                    'Authorization': req.get('Authorization')
+                    'Authorization': req.session && req.session.authorization
                 }),
                 forever: constants.FOREVER_ON,
                 rejectUnauthorized: false,
@@ -75,7 +75,7 @@
                 uri: utils.confdPort(api_server) + '/api/config/project',
                 method: 'POST',
                 headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
-                    'Authorization': req.get('Authorization')
+                    'Authorization': req.session && req.session.authorization
                 }),
                 forever: constants.FOREVER_ON,
                 json: data,
@@ -115,7 +115,7 @@
                 uri: utils.confdPort(api_server) + '/api/config/project',
                 method: 'PUT',
                 headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
-                    'Authorization': req.get('Authorization')
+                    'Authorization': req.session && req.session.authorization
                 }),
                 forever: constants.FOREVER_ON,
                 json: data,
@@ -157,7 +157,7 @@
         _.extend(requestHeaders,
             constants.HTTP_HEADERS.accept.data,
             constants.HTTP_HEADERS.content_type.data, {
-                'Authorization': req.get('Authorization')
+                'Authorization': req.session && req.session.authorization
             });
         rp({
             url: url,
diff --git a/skyquake/framework/core/modules/api/restconf.js b/skyquake/framework/core/modules/api/restconf.js
index 5ba0eb5..03f2721 100644
--- a/skyquake/framework/core/modules/api/restconf.js
+++ b/skyquake/framework/core/modules/api/restconf.js
@@ -45,7 +45,7 @@
             url: uri + url + '?deep',
             method: 'GET',
             headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
-                'Authorization': req.get('Authorization')
+                'Authorization': req.session && req.session.authorization
             }),
             forever: constants.FOREVER_ON,
             rejectUnauthorized: false,
diff --git a/skyquake/framework/core/modules/api/sessions.js b/skyquake/framework/core/modules/api/sessions.js
new file mode 100644
index 0000000..c8a0223
--- /dev/null
+++ b/skyquake/framework/core/modules/api/sessions.js
@@ -0,0 +1,205 @@
+/*
+ * 
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
+ *
+ */
+
+/**
+ * sessions api module. Provides API functions for sessions
+ * @module framework/core/modules/api/sessions
+ * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
+ */
+
+var Promise = require('bluebird');
+var constants = require('../../api_utils/constants');
+var utils = require('../../api_utils/utils');
+var request = utils.request;
+var rp = require('request-promise');
+var sessionsAPI = {};
+var _ = require('lodash');
+var base64 = require('base-64');
+var APIVersion = '/v2';
+
+function logAndReject(mesg, reject) {
+    res.errorMessage = {
+        error: mesg
+    }
+    console.log(mesg);
+    reject(res);
+}
+
+function logAndRedirectToLogin(mesg, res, req) {
+    console.log(mesg);
+    res.render('login.html?api_server=' + req.query['api_server']);
+    res.end();
+}
+
+sessionsAPI.create = function(req, res) {
+    var api_server = req.query["api_server"];
+    var uri = utils.confdPort(api_server);
+    var login_url = uri + APIVersion + '/api/login';
+    var project_url = uri + APIVersion + '/api/operational/project';
+    var authorization_header_string = 'Basic ' + base64.encode(req.body['username'] + ':' + req.body['password']);
+    return new Promise(function(resolve, reject) {
+        Promise.all([
+            rp({
+                url: login_url,
+                method: 'POST',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': authorization_header_string
+                }),
+                forever: constants.FOREVER_ON,
+                rejectUnauthorized: constants.REJECT_UNAUTHORIZED,
+                resolveWithFullResponse: true
+            }),
+            rp({
+                url: project_url,
+                method: 'GET',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
+                    'Authorization': authorization_header_string
+                }),
+                forever: constants.FOREVER_ON,
+                rejectUnauthorized: constants.REJECT_UNAUTHORIZED,
+                resolveWithFullResponse: true
+            })
+
+        ]).then(function(results) {
+            // results[0].statusCode => 200/201
+            // results[1].body.collection['rw-project:project'] => List of projects OR 204 with no content
+            if (results[0].statusCode != constants.HTTP_RESPONSE_CODES.SUCCESS.OK) {
+                var errorMsg = 'Invalid credentials provided!';
+                logAndRedirectToLogin(errorMsg, res, req);
+                return;
+            }
+
+            var username = req.body['username'];
+            var project_list_for_user = [];
+
+            if (results[1].statusCode == constants.HTTP_RESPONSE_CODES.SUCCESS.NO_CONTENT) {
+                console.log('No projects added or user ', username ,' not privileged to view projects.');
+            } else {
+                // go through projects and get list of projects that this user belongs to.
+                // pick first one as default project?
+
+                var projects = JSON.parse(results[1].body).collection['rw-project:project'];
+                projects && projects.map(function(project) {
+                    project['project-config'] &&
+                    project['project-config']['user'] &&
+                    project['project-config']['user'].map(function(user) {
+                        if (user['user-name'] == username) {
+                            project_list_for_user.push(project.name);
+                        }
+                    });
+                });
+
+                req.session.projectId = (project_list_for_user.length > 0) && project_list_for_user[0];
+            }
+
+            req.session.authorization = authorization_header_string;
+            req.session.loggedIn = true;
+
+            var successMsg = 'User =>' + username + ' successfully logged in.';
+            successMsg += req.session.projectId ? 'Project =>' + req.session.projectId + ' set as default.' : '';
+
+            console.log(successMsg);
+
+            var response = {
+                statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.CREATED,
+                data: JSON.stringify({
+                    status: successMsg
+                })
+            };
+            resolve(response);
+
+        }).catch(function(error) {
+            // Something went wrong - Redirect to /login
+            var errorMsg = 'Error logging in or getting list of projects. Error: ' + error;
+            console.log(errorMsg);
+            logAndRedirectToLogin(errorMsg, res, req);
+        });
+    })
+};
+
+sessionsAPI.addProjectToSession = function(req, res) {
+    return new Promise(function(resolve, reject) {
+        if (req.session && req.session.loggedIn == true) {
+            req.session.projectId = req.params.projectId;
+            var successMsg = 'Added project' + projectId + ' to session' + req.sessionID;
+            console.log(successMsg);
+
+            return resolve ({
+                statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK,
+                data: JSON.stringify({
+                    status: successMsg
+                })
+            });
+        }
+
+        var errorMsg = 'Session does not exist or not logged in';
+        logAndReject(errorMsg, reject);
+    });
+}
+
+sessionsAPI.delete = function(req, res) {
+    var reqRef = req;
+    var res = res;
+    var api_server = req.query["api_server"];
+    var uri = utils.confdPort(api_server);
+    var url = uri + '/api/logout';
+    return new Promise(function(resolve, reject) {
+        Promise.all([
+            rp({
+                url: url,
+                method: 'POST',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                rejectUnauthorized: constants.REJECT_UNAUTHORIZED
+            }),
+            new Promise(function(success, failure) {
+                req.session.destroy(function(err) {
+                    if (err) {
+                        var errorMsg = 'Error deleting session. Error: ' + err;
+                        console.log(errorMsg);
+                        success({
+                            status: 'error',
+                            message: errorMsg
+                        });
+                    }
+
+                    var successMsg = 'Success deleting session';
+                    console.log(successMsg);
+
+                    success({
+                        status: 'success',
+                        message: successMsg
+                    });
+                });
+            })
+        ]).then(function(result) {
+            // assume the session was deleted!
+            var message = 'Session was deleted.'
+            logAndRedirectToLogin(message, res, req);
+
+        }).catch(function(error) {
+            var message = 'Error deleting session or logging out. Error:' + error;
+            logAndRedirectToLogin(message, res, req);
+        });
+    });
+}
+
+
+module.exports = sessionsAPI;
diff --git a/skyquake/framework/core/modules/api/userManagementAPI.js b/skyquake/framework/core/modules/api/userManagementAPI.js
index 3972122..e88a5dc 100644
--- a/skyquake/framework/core/modules/api/userManagementAPI.js
+++ b/skyquake/framework/core/modules/api/userManagementAPI.js
@@ -36,7 +36,7 @@
                 uri: utils.confdPort(api_server) + '/api/operational/user-config/users',
                 method: 'GET',
                 headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
-                    'Authorization': req.get('Authorization')
+                    'Authorization': req.session && req.session.authorization
                 }),
                 forever: constants.FOREVER_ON,
                 rejectUnauthorized: false,
@@ -75,7 +75,7 @@
                 uri: utils.confdPort(api_server) + '/api/config/user-config',
                 method: 'POST',
                 headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
-                    'Authorization': req.get('Authorization')
+                    'Authorization': req.session && req.session.authorization
                 }),
                 forever: constants.FOREVER_ON,
                 json: data,
@@ -115,7 +115,7 @@
             uri: utils.confdPort(api_server) + '/api/operations/change-password',
             method: 'POST',
             headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
-                'Authorization': req.get('Authorization')
+                'Authorization': req.session && req.session.authorization
             }),
             forever: constants.FOREVER_ON,
             json: {
@@ -136,7 +136,7 @@
                 uri: utils.confdPort(api_server) + '/api/config/user-config',
                 method: 'PUT',
                 headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
-                    'Authorization': req.get('Authorization')
+                    'Authorization': req.session && req.session.authorization
                 }),
                 forever: constants.FOREVER_ON,
                 json: data,
@@ -179,7 +179,7 @@
         _.extend(requestHeaders,
             constants.HTTP_HEADERS.accept.data,
             constants.HTTP_HEADERS.content_type.data, {
-                'Authorization': req.get('Authorization')
+                'Authorization': req.session && req.session.authorization
             });
         rp({
             url: url,
diff --git a/skyquake/framework/core/modules/routes/configuration.js b/skyquake/framework/core/modules/routes/configuration.js
index b789ff0..37d87fe 100644
--- a/skyquake/framework/core/modules/routes/configuration.js
+++ b/skyquake/framework/core/modules/routes/configuration.js
@@ -74,7 +74,7 @@
             uri: uri,
             method: 'GET',
             headers: _.extend({}, {
-                'Authorization': req.get('Authorization'),
+                'Authorization': req.session && req.session.authorization,
                 forever: CONSTANTS.FOREVER_ON,
                 rejectUnauthorized: false,
             })
diff --git a/skyquake/framework/core/modules/routes/navigation.js b/skyquake/framework/core/modules/routes/navigation.js
index 82c7ec5..9b8fbf7 100644
--- a/skyquake/framework/core/modules/routes/navigation.js
+++ b/skyquake/framework/core/modules/routes/navigation.js
@@ -37,8 +37,20 @@
     extended: true
 }));
 
-Router.get('/', cors(), function(req, res, next) {
-	res.redirect('/launchpad/?api_server=' + req.protocol + '://' + configurationAPI.globalConfiguration.get().api_server + '&upload_server=' + req.protocol + '://' + (configurationAPI.globalConfiguration.get().upload_server || req.hostname));
+Router.get('/login.html', cors(), function(req, res) {
+	res.render('login.html');
+	res.end();
+});
+
+Router.get('/', cors(), function(req, res) {
+	var api_server = req.query['api_server'] || (req.protocol + '://' + configurationAPI.globalConfiguration.get().api_server);
+	if (req.session.loggedIn) {
+		console.log('Logged in. Redirect to launchpad')
+		res.redirect('/launchpad/?api_server=' + api_server + '&upload_server=' + req.protocol + '://' + (configurationAPI.globalConfiguration.get().upload_server || req.hostname));
+	} else {
+		console.log('Redirect to login.html');
+		res.redirect('login.html?api_server=' + api_server);
+	}
 });
 
 Router.get('/nav', cors(), function(req, res) {
diff --git a/skyquake/framework/core/modules/routes/sessions.js b/skyquake/framework/core/modules/routes/sessions.js
new file mode 100644
index 0000000..bd2179b
--- /dev/null
+++ b/skyquake/framework/core/modules/routes/sessions.js
@@ -0,0 +1,62 @@
+
+/*
+ *
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
+ *
+ */
+
+/**
+ * Node sessions routes module.
+ * Provides a RESTful API to manage sessions.
+ * @module framework/core/modules/routes/sessions
+ * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
+ */
+
+var cors = require('cors');
+var bodyParser = require('body-parser');
+var sessionsAPI = require('../api/sessions');
+var Router = require('express').Router();
+var utils = require('../../api_utils/utils');
+var CONSTANTS = require('../../api_utils/constants.js');
+var request = require('request');
+var _ = require('lodash');
+
+Router.use(bodyParser.json());
+Router.use(cors());
+Router.use(bodyParser.urlencoded({
+    extended: true
+}));
+
+Router.post('/session', cors(), function(req, res) {
+    sessionsAPI.create(req, res).then(function(data) {
+        utils.sendSuccessResponse(data, res);
+	});
+});
+
+// For project switcher UI
+Router.put('/session/:projectId', cors(), function(req, res) {
+    sessionsAPI.addProjectToSession(req, res).then(function(data) {
+        utils.sendSuccessResponse(data, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+
+Router.delete('/session', cors(), function(req, res) {
+    sessionsAPI.delete(req, res);
+});
+
+
+module.exports = Router;
diff --git a/skyquake/framework/core/views/login.html b/skyquake/framework/core/views/login.html
new file mode 100644
index 0000000..eb5e714
--- /dev/null
+++ b/skyquake/framework/core/views/login.html
@@ -0,0 +1,118 @@
+<html>
+<head>
+<style>
+    html, body {
+        height:100%;
+        width:100%;
+        background: #f1f1f1;
+    }
+
+    #loginForm {
+        display: flex;
+        flex-direction: column;
+        height: 100%;
+        text-align: center;
+        align-items: center;
+    }
+
+    #loginForm .logo {
+        background: url('/img/svg/osm-logo_color_rgb.svg') no-repeat center;
+        background-size: contain;
+        width: 154px;
+        height: 102px;
+        margin-left: auto;
+        margin-right: auto;
+        margin-top: 150px;
+        margin-bottom: 20px;
+    }
+
+    #loginForm input {
+        width: 550px;
+        height: 65px;
+        min-width: auto;
+        margin-bottom: 40px;
+        box-shadow: inset 0 1px 2px rgba(0, 0, 0, .39), 0 -1px 1px #fff, 0 1px 0 #fff;
+        font-size: 20px;
+        padding-left: 25px;
+    }
+
+    #loginForm #submit {
+        display: inline-block;
+        -webkit-box-shadow: 4px 4px 1px 0 #d9d9d9;
+        -moz-box-shadow: 4px 4px 1px 0 #d9d9d9;
+        box-shadow: 4px 4px 1px 0 #d9d9d9;
+        background-color: #333;
+        color: #fff;
+        text-decoration: none;
+    }
+
+    #loginForm .title {
+        margin-bottom: 40px;
+        font-size: 1.625rem;
+        font-weight: 400;
+        text-decoration: none;
+        text-transform: uppercase;
+        font-family: roboto-thin, Helvetica, Arial, sans-serif;
+    }
+
+</style>
+<title>Login Page</title>
+<script src='/jquery'></script>
+<script>
+
+function getSearchParams(url) {
+    var a = document.createElement('a');
+    a.href = url;
+    var params = {};
+    var items = a.search.replace('?', '').split('&');
+    for (var i = 0; i < items.length; i++) {
+      if (items[i].length > 0) {
+        var key_value = items[i].split('=');
+        params[key_value[0]] = key_value[1];
+      }
+    }
+    return params;
+}
+
+$(document).ready(function() {
+    var username;
+    var pass;
+    var api_server = getSearchParams(window.location).api_server;
+    $('#submit').click(function() {
+        username=$('#username').val();
+        pass=$('#password').val();
+        /*
+        * Perform some validation here.
+        */
+        $.ajax({
+            url: '/session?api_server=' + api_server,
+            type: 'POST',
+            data: {
+                username: username,
+                password: pass
+            },
+            success: function(data) {
+                window.location.href='/?api_server=' + api_server;
+            }
+        });
+    });
+
+    $('#loginForm').on('keyup', function(e) {
+        if (e.keyCode == 13) {
+            $('#submit').click();
+        }
+    });
+});
+
+</script>
+</head>
+<body>
+    <form id='loginForm' autocomplete='on'>
+        <div class='logo'> </div>
+        <h1 class='title'>Launchpad Login</h1>
+        <input type='text' size='40' placeholder='Username' id='username'><br />
+        <input type='password' size='40' placeholder='Password' id='password'><br />
+        <input type='button' value='Submit' id='submit'>
+    </form>
+</body>
+</html>
\ No newline at end of file
diff --git a/skyquake/framework/utils/utils.js b/skyquake/framework/utils/utils.js
index e8e9ad1..be3278d 100644
--- a/skyquake/framework/utils/utils.js
+++ b/skyquake/framework/utils/utils.js
@@ -129,8 +129,9 @@
 }
 
 Utils.addAuthorizationStub = function(xhr) {
-    var Auth = window.sessionStorage.getItem("auth");
-    xhr.setRequestHeader('Authorization', 'Basic ' + Auth);
+    // NO-OP now that we are dealing with it on the server
+    // var Auth = window.sessionStorage.getItem("auth");
+    // xhr.setRequestHeader('Authorization', 'Basic ' + Auth);
 };
 
 Utils.getByteDataWithUnitPrefix = function(number, precision) {
@@ -208,10 +209,22 @@
     window.sessionStorage.removeItem("auth");
     AuthActions.notAuthenticated();
     window.sessionStorage.setItem("locationRefHash", window.location.hash);
+    $.ajax({
+        url: '//' + window.location.hostname + ':' + window.location.port + '/session?api_server=' + API_SERVER,
+        type: 'DELETE',
+        success: function(data) {
+            console.log('User logged out');
+        },
+        error: function(data) {
+            console.log('Problem logging user out');
+        }
+    });
+
+
     if (callback) {
         callback();
     } else {
-        window.location.hash = Utils.loginHash;
+        window.location.replace(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/?api_server=' + API_SERVER);
     }
 }
 Utils.isNotAuthenticated = function(windowLocation, callback) {