<commit_before>"use strict";

var bodyParser = require("body-parser");
var login = require("connect-ensure-login");
var express = require("express");
var exphbs  = require("express-handlebars");
var session = require("express-session");
var morgan = require("morgan");
var oauth2orize = require("oauth2orize");
var passportModule = require("passport");
var LocalStrategy = require("passport-local").Strategy;
var ClientPasswordStrategy = require("passport-oauth2-client-password").Strategy;

var config = require("../config"); // TODO: export up to options in gpii.oauth2.authServer

var fluid = require("infusion");
require("../gpii-oauth2-datastore");
require("../oauth2Utilities");
require("./userService");
require("./authorizationService");
require("./clientService");

var gpii = fluid.registerNamespace("gpii");

// gpii.oauth2.oauth2orizeServer
// -----------------------------

gpii.oauth2.createOauth2orizeServer = function () {
    return oauth2orize.createServer();
};

// Unbound references: {clientService} and {authorizationService}
fluid.defaults("gpii.oauth2.oauth2orizeServer", {
    gradeNames: ["fluid.eventedComponent", "autoInit"],
    members: {
        oauth2orizeServer: {
            expander: {
                func: "gpii.oauth2.createOauth2orizeServer"
            }
        }
    },
    listeners: {
        onCreate: {
            listener: "gpii.oauth2.oauth2orizeServer.listenOauth2orize",
            args: ["{that}.oauth2orizeServer", "{clientService}", "{authorizationService}"]
        }
    }
});

// TODO what name here?
gpii.oauth2.oauth2orizeServer.listenOauth2orize = function (oauth2orizeServer, clientService, authorizationService) {
    oauth2orizeServer.serializeClient(function (client, done) {
        return done(null, client.id);
    });

    oauth2orizeServer.deserializeClient(function (id, done) {
        return done(null, clientService.getClientById(id));
    });

    oauth2orizeServer.grant(oauth2orize.grant.code(function (client, redirectUri, user, ares, done) {
        return done(null, authorizationService.grantAuthorizationCode(user.id, client.id, redirectUri));
    }));

    oauth2orizeServer.exchange(oauth2orize.exchange.code(function (client, code, redirectUri, done) {
        return done(null, authorizationService.exchangeCodeForAccessToken(code, client.id, redirectUri));
    }));
};

// gpii.oauth2.passport
// --------------------

gpii.oauth2.createPassport = function () {
    return new passportModule.Passport();
};

fluid.defaults("gpii.oauth2.passport", {
    gradeNames: ["fluid.eventedComponent", "autoInit"],
    members: {
        passport: {
            expander: {
                func: "gpii.oauth2.createPassport"
            }
        }
    },
    listeners: {
        onCreate: {
            listener: "gpii.oauth2.passport.listenPassport",
            args: ["{that}.passport", "{userService}", "{clientService}"]
        }
    }
});

// TODO what name here?
gpii.oauth2.passport.listenPassport = function (passport, userService, clientService) {
    passport.serializeUser(function (user, done) {
        return done(null, user.id);
    });

    passport.deserializeUser(function(id, done) {
        return done(null, userService.getUserById(id));
    });

    passport.use(new LocalStrategy(
        function (username, password, done) {
            return done(null, userService.authenticateUser(username, password));
        }
    ));

    // ClientPasswordStrategy reads the client_id and client_secret from the
    // request body. Can also use a BasicStrategy for HTTP Basic authentication.
    passport.use(new ClientPasswordStrategy(
        function (oauth2ClientId, oauth2ClientSecret, done) {
            return done(null, clientService.authenticateClient(oauth2ClientId, oauth2ClientSecret));
        }
    ));
};

// gpii.oauth2.authServer
// ----------------------

gpii.oauth2.createExpressApp = function () {
    return express();
};

// An empty grade to guide resolution of IoC expressions onto a suitable gpii.oauth2.datastore
fluid.defaults("gpii.oauth2.datastoreHolder", {
    gradeNames: ["fluid.eventedComponent", "autoInit"]
});

fluid.defaults("gpii.oauth2.authServer", {
    gradeNames: ["fluid.eventedComponent", "gpii.oauth2.datastoreHolder", "autoInit"],
    members: {
        expressApp: {
            expander: {
                func: "gpii.oauth2.createExpressApp"
            }
        }
    },
    components: {
        oauth2orizeServer: {
            type: "gpii.oauth2.oauth2orizeServer"
        },
        passport: {
            type: "gpii.oauth2.passport"
        },
        dataStore: {
            type: "gpii.oauth2.datastoreWithSampleData" // variants here
        },
        authorizationService: {
            type: "gpii.oauth2.authorizationService",
            options: {
                components: {
                    dataStore: "{gpii.oauth2.datastoreHolder}.dataStore"
                }
            }
        },
        clientService: {
            type: "gpii.oauth2.clientService",
            options: {
                components: {
                    dataStore: "{gpii.oauth2.datastoreHolder}.dataStore"
                }
            }
        },
        userService: {
            type: "gpii.oauth2.userService",
            options: {
                components: {
                    dataStore: "{gpii.oauth2.datastoreHolder}.dataStore"
                }
            }
        }
    },
    listeners: {
        onCreate: {
            listener: "gpii.oauth2.authServer.listenApp",
            args: ["{that}.expressApp", "{that}.oauth2orizeServer.oauth2orizeServer",
                "{that}.clientService", "{that}.authorizationService", "{that}.passport.passport"]
        }
    }
});

/*
 * Manually performs the login routing, similar to the passport
 * middleware, but with the addition of adding a "loginFailed"
 * flag to the session. This is useful for displaying an error
 * message on the login screen after an unsucessful login attempt.
 *
 * @param {object} passport - an instance of a passport object
 *
 * @param {object} options - Like the passport middleware it takes in
 *                           successReturnToOrRedirect and failureRedirect
 *                           paths.
 */
gpii.oauth2.authServer.loginRouting = function (passport, options) {
    return function (req, res, next) {
        passport.authenticate("local", function(err, user) {
            if (err) {
                return next(err);
            }

            if (!user) {
                req.session.loginFailed = true;
                return res.redirect(options.failureRedirect);
            }

            req.logIn(user, function(err) {
                var url = options.successReturnToOrRedirect;
                if (err) {
                    return next(err);
                }
                if (req.session && req.session.returnTo) {
                    url = req.session.returnTo;<commit_msg>GPII-1034: Adding attribution to login routing<commit_after>"use strict";

var bodyParser = require("body-parser");
var login = require("connect-ensure-login");
var express = require("express");
var exphbs  = require("express-handlebars");
var session = require("express-session");
var morgan = require("morgan");
var oauth2orize = require("oauth2orize");
var passportModule = require("passport");
var LocalStrategy = require("passport-local").Strategy;
var ClientPasswordStrategy = require("passport-oauth2-client-password").Strategy;

var config = require("../config"); // TODO: export up to options in gpii.oauth2.authServer

var fluid = require("infusion");
require("../gpii-oauth2-datastore");
require("../oauth2Utilities");
require("./userService");
require("./authorizationService");
require("./clientService");

var gpii = fluid.registerNamespace("gpii");

// gpii.oauth2.oauth2orizeServer
// -----------------------------

gpii.oauth2.createOauth2orizeServer = function () {
    return oauth2orize.createServer();
};

// Unbound references: {clientService} and {authorizationService}
fluid.defaults("gpii.oauth2.oauth2orizeServer", {
    gradeNames: ["fluid.eventedComponent", "autoInit"],
    members: {
        oauth2orizeServer: {
            expander: {
                func: "gpii.oauth2.createOauth2orizeServer"
            }
        }
    },
    listeners: {
        onCreate: {
            listener: "gpii.oauth2.oauth2orizeServer.listenOauth2orize",
            args: ["{that}.oauth2orizeServer", "{clientService}", "{authorizationService}"]
        }
    }
});

// TODO what name here?
gpii.oauth2.oauth2orizeServer.listenOauth2orize = function (oauth2orizeServer, clientService, authorizationService) {
    oauth2orizeServer.serializeClient(function (client, done) {
        return done(null, client.id);
    });

    oauth2orizeServer.deserializeClient(function (id, done) {
        return done(null, clientService.getClientById(id));
    });

    oauth2orizeServer.grant(oauth2orize.grant.code(function (client, redirectUri, user, ares, done) {
        return done(null, authorizationService.grantAuthorizationCode(user.id, client.id, redirectUri));
    }));

    oauth2orizeServer.exchange(oauth2orize.exchange.code(function (client, code, redirectUri, done) {
        return done(null, authorizationService.exchangeCodeForAccessToken(code, client.id, redirectUri));
    }));
};

// gpii.oauth2.passport
// --------------------

gpii.oauth2.createPassport = function () {
    return new passportModule.Passport();
};

fluid.defaults("gpii.oauth2.passport", {
    gradeNames: ["fluid.eventedComponent", "autoInit"],
    members: {
        passport: {
            expander: {
                func: "gpii.oauth2.createPassport"
            }
        }
    },
    listeners: {
        onCreate: {
            listener: "gpii.oauth2.passport.listenPassport",
            args: ["{that}.passport", "{userService}", "{clientService}"]
        }
    }
});

// TODO what name here?
gpii.oauth2.passport.listenPassport = function (passport, userService, clientService) {
    passport.serializeUser(function (user, done) {
        return done(null, user.id);
    });

    passport.deserializeUser(function(id, done) {
        return done(null, userService.getUserById(id));
    });

    passport.use(new LocalStrategy(
        function (username, password, done) {
            return done(null, userService.authenticateUser(username, password));
        }
    ));

    // ClientPasswordStrategy reads the client_id and client_secret from the
    // request body. Can also use a BasicStrategy for HTTP Basic authentication.
    passport.use(new ClientPasswordStrategy(
        function (oauth2ClientId, oauth2ClientSecret, done) {
            return done(null, clientService.authenticateClient(oauth2ClientId, oauth2ClientSecret));
        }
    ));
};

// gpii.oauth2.authServer
// ----------------------

gpii.oauth2.createExpressApp = function () {
    return express();
};

// An empty grade to guide resolution of IoC expressions onto a suitable gpii.oauth2.datastore
fluid.defaults("gpii.oauth2.datastoreHolder", {
    gradeNames: ["fluid.eventedComponent", "autoInit"]
});

fluid.defaults("gpii.oauth2.authServer", {
    gradeNames: ["fluid.eventedComponent", "gpii.oauth2.datastoreHolder", "autoInit"],
    members: {
        expressApp: {
            expander: {
                func: "gpii.oauth2.createExpressApp"
            }
        }
    },
    components: {
        oauth2orizeServer: {
            type: "gpii.oauth2.oauth2orizeServer"
        },
        passport: {
            type: "gpii.oauth2.passport"
        },
        dataStore: {
            type: "gpii.oauth2.datastoreWithSampleData" // variants here
        },
        authorizationService: {
            type: "gpii.oauth2.authorizationService",
            options: {
                components: {
                    dataStore: "{gpii.oauth2.datastoreHolder}.dataStore"
                }
            }
        },
        clientService: {
            type: "gpii.oauth2.clientService",
            options: {
                components: {
                    dataStore: "{gpii.oauth2.datastoreHolder}.dataStore"
                }
            }
        },
        userService: {
            type: "gpii.oauth2.userService",
            options: {
                components: {
                    dataStore: "{gpii.oauth2.datastoreHolder}.dataStore"
                }
            }
        }
    },
    listeners: {
        onCreate: {
            listener: "gpii.oauth2.authServer.listenApp",
            args: ["{that}.expressApp", "{that}.oauth2orizeServer.oauth2orizeServer",
                "{that}.clientService", "{that}.authorizationService", "{that}.passport.passport"]
        }
    }
});

/*
 * Based on the Custom Callback example from the passportjs guide.
 * http://passportjs.org/guide/authenticate/
 * Licensed under CC BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/) 
 *
 * Manually performs the login routing, similar to the passport
 * middleware, but with the addition of adding a "loginFailed"
 * flag to the session. This is useful for displaying an error
 * message on the login screen after an unsucessful login attempt.
 *
 * @param {object} passport - an instance of a passport object
 *
 * @param {object} options - Like the passport middleware it takes in
 *                           successReturnToOrRedirect and failureRedirect
 *                           paths.
 */
gpii.oauth2.authServer.loginRouting = function (passport, options) {
    return function (req, res, next) {
        passport.authenticate("local", function(err, user) {
            if (err) {
                return next(err);
            }

            if (!user) {
                req.session.loginFailed = true;
                return res.redirect(options.failureRedirect);
            }

            req.logIn(user, function(err) {
                var url = options.successReturnToOrRedirect;
                if (err) {
                    return next(err);
                }
                if (req.session && req.session.returnTo) {
                    url = req.session.returnTo;
{'fraction_non_alphanumeric': 0.13064687168610817, 'fraction_numerical': 0.009331919406150583, 'mean_word_length': 2.3737181015979014, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1068801', 'n_tokens_mistral': 4211, 'n_tokens_neox': 4104, 'n_words': 775}