Active Directory primary athentication support
This commit is contained in:
Родитель
5964b974db
Коммит
2937a97ffe
6
app.js
6
app.js
|
@ -20,7 +20,11 @@ app.initializeApplication = function init(config, configurationError, callback)
|
|||
};
|
||||
}
|
||||
app.set('runtimeConfig', config);
|
||||
require('./middleware/')(app, express, config, __dirname, redisClient, error);
|
||||
try {
|
||||
require('./middleware/')(app, express, config, __dirname, redisClient, error);
|
||||
} catch (middlewareError) {
|
||||
error = middlewareError;
|
||||
}
|
||||
if (!error) {
|
||||
app.use('/', require('./routes/'));
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ module.exports = function translateEnvironmentToConfiguration(legacyConfiguratio
|
|||
websiteSku: configurationHelper.get('WEBSITE_SKU'),
|
||||
expectedSslCertificate: configurationHelper.get('EXPECTED_SSL_CERTIFICATE'),
|
||||
allowHttp: configurationHelper.get('DEBUG_ALLOW_HTTP'),
|
||||
showDebugFooter: configurationHelper.get('DEBUG_SHOW_FOOTER'),
|
||||
showDebugFooter: (configurationHelper.get('DEBUG_SHOW_FOOTER') === true || configurationHelper.get('DEBUG_SHOW_FOOTER') === 'true'),
|
||||
corporate: {
|
||||
userProfilePrefix: configurationHelper.get('CORPORATE_PROFILE_PREFIX'),
|
||||
trainingResources: require('./resources.json'),
|
||||
|
@ -61,6 +61,7 @@ module.exports = function translateEnvironmentToConfiguration(legacyConfiguratio
|
|||
cla: utils.arrayFromString(configurationHelper.get('FRIENDS_CLA')),
|
||||
employeeData: utils.arrayFromString(configurationHelper.get('FRIENDS_DATA')),
|
||||
},
|
||||
primaryAuthenticationScheme: configurationHelper.get('PRIMARY_AUTHENTICATION_SCHEME'),
|
||||
// GitHub application properties and secrets
|
||||
github: {
|
||||
clientId: configurationHelper.get('GITHUB_CLIENT_ID'),
|
||||
|
|
14
data.js
14
data.js
|
@ -223,7 +223,7 @@ DataClient.prototype.removeError = function (partitionKey, rowKey, callback) {
|
|||
DataClient.prototype.getActiveErrors = function (correlationId, callback) {
|
||||
var dc = this;
|
||||
// Correlation ID is optional
|
||||
if (typeof (correlationId) == 'function') {
|
||||
if (typeof (correlationId) === 'function') {
|
||||
callback = correlationId;
|
||||
correlationId = undefined;
|
||||
}
|
||||
|
@ -305,7 +305,7 @@ DataClient.prototype.mergeIntoEntity = function mit(entity, obj, callback) {
|
|||
|
||||
DataClient.prototype.createEntity = function ce(partitionKey, rowKey, obj, callback) {
|
||||
var dc = this;
|
||||
if (typeof (obj) == 'function') {
|
||||
if (typeof (obj) === 'function') {
|
||||
callback = obj;
|
||||
obj = undefined;
|
||||
}
|
||||
|
@ -385,7 +385,7 @@ DataClient.prototype.getUserLinkByUsername = function gulbyu(githubUsername, cal
|
|||
this.getUserLinkByProperty('ghu', githubUsername, function (error, data) {
|
||||
if (error) return callback(error);
|
||||
if (data && data.length) {
|
||||
if (data.length == 1) {
|
||||
if (data.length === 1) {
|
||||
callback(null, data[0]);
|
||||
} else {
|
||||
if (data.length === 0) {
|
||||
|
@ -527,12 +527,12 @@ DataClient.prototype.getPendingApprovals = function getPendingApprovals(teamsIn,
|
|||
var dc = this;
|
||||
var teams = null;
|
||||
var i;
|
||||
if (typeof teamsIn == 'number') {
|
||||
if (typeof teamsIn === 'number') {
|
||||
teams = [teamsIn.toString()];
|
||||
}
|
||||
else if (typeof teamsIn == 'string') {
|
||||
else if (typeof teamsIn === 'string') {
|
||||
teams = [teamsIn];
|
||||
} else if (typeof teamsIn == 'function') {
|
||||
} else if (typeof teamsIn === 'function') {
|
||||
callback = teamsIn;
|
||||
teams = []; // Special case: empty list means all pending approvals
|
||||
} else {
|
||||
|
@ -611,7 +611,7 @@ DataClient.prototype.getApprovalRequest = function gar(requestId, callback) {
|
|||
|
||||
DataClient.prototype.getPendingApprovalsForUserId = function gpeaf(githubid, callback) {
|
||||
var dc = this;
|
||||
if (typeof githubid == 'number') {
|
||||
if (typeof githubid === 'number') {
|
||||
githubid = githubid.toString();
|
||||
}
|
||||
var query = new azure.TableQuery()
|
||||
|
|
|
@ -14,6 +14,7 @@ module.exports = function configureErrorRoutes(app, initializationError) {
|
|||
app.use((req, res, next) => {
|
||||
var error = new Error('Application initialization error');
|
||||
error.detailed = initializationError.message || null;
|
||||
error.innerError = initializationError;
|
||||
return next(error);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,50 +9,54 @@ const bodyParser = require('body-parser');
|
|||
const compression = require('compression');
|
||||
|
||||
module.exports = function initMiddleware(app, express, config, dirname, redisClient, initializationError) {
|
||||
if (!initializationError) {
|
||||
if (config.allowHttp) {
|
||||
console.warn('WARNING: Allowing HTTP for local debugging');
|
||||
} else {
|
||||
app.use(require('./sslify'));
|
||||
app.use(require('./hsts'));
|
||||
}
|
||||
require('./appInsights')(config);
|
||||
if (!initializationError) {
|
||||
if (config.allowHttp) {
|
||||
console.warn('WARNING: Allowing HTTP for local debugging');
|
||||
} else {
|
||||
app.use(require('./sslify'));
|
||||
app.use(require('./hsts'));
|
||||
}
|
||||
require('./appInsights')(config);
|
||||
}
|
||||
|
||||
app.set('views', path.join(dirname, 'views'));
|
||||
app.set('view engine', 'jade');
|
||||
app.set('view cache', false);
|
||||
app.set('views', path.join(dirname, 'views'));
|
||||
app.set('view engine', 'jade');
|
||||
app.set('view cache', false);
|
||||
|
||||
app.use(favicon(dirname + '/public/favicon.ico'));
|
||||
app.use(favicon(dirname + '/public/favicon.ico'));
|
||||
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({ extended: false }));
|
||||
app.use(compression());
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({ extended: false }));
|
||||
app.use(compression());
|
||||
|
||||
var passport;
|
||||
if (!initializationError) {
|
||||
app.use(require('./session')(config, redisClient));
|
||||
try {
|
||||
passport = require('./passport-config')(app, config);
|
||||
} catch (passportError) {
|
||||
initializationError = passportError;
|
||||
}
|
||||
var passport;
|
||||
if (!initializationError) {
|
||||
app.use(require('./session')(config, redisClient));
|
||||
try {
|
||||
passport = require('./passport-config')(app, config);
|
||||
} catch (passportError) {
|
||||
initializationError = passportError;
|
||||
}
|
||||
}
|
||||
|
||||
app.use(express.static(path.join(dirname, 'public')));
|
||||
app.use(express.static(path.join(dirname, 'public')));
|
||||
|
||||
app.use(require('./scrubbedUrl'));
|
||||
app.use(require('./logger'));
|
||||
if (!initializationError && config.websiteSku && !config.allowHttp) {
|
||||
app.use(require('./requireSecureAppService'));
|
||||
app.use(require('./scrubbedUrl'));
|
||||
app.use(require('./logger'));
|
||||
if (!initializationError && config.websiteSku && !config.allowHttp) {
|
||||
app.use(require('./requireSecureAppService'));
|
||||
}
|
||||
app.use(require('./correlationId'));
|
||||
app.use(require('./locals'));
|
||||
|
||||
if (!initializationError) {
|
||||
require('./passport-routes')(app, passport, config);
|
||||
if (config.onboarding && config.onboarding.length && config.onboarding.length > 0) {
|
||||
require('./onboarding')(app, config);
|
||||
}
|
||||
app.use(require('./correlationId'));
|
||||
app.use(require('./locals'));
|
||||
}
|
||||
|
||||
if (!initializationError) {
|
||||
require('./passport-routes')(app, passport);
|
||||
if (config.onboarding && config.onboarding.length && config.onboarding.length > 0) {
|
||||
require('./onboarding')(app, config);
|
||||
}
|
||||
}
|
||||
if (initializationError) {
|
||||
throw initializationError;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,54 +3,72 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
const passport = require('passport');
|
||||
'use strict';
|
||||
|
||||
const passport = require('passport');
|
||||
const utils = require('../utils');
|
||||
|
||||
const GitHubStrategy = require('passport-github').Strategy;
|
||||
const OIDCStrategy = require('passport-azure-ad').OIDCStrategy;
|
||||
|
||||
function githubResponseToSubset(accessToken, refreshToken, profile, done) {
|
||||
let subset = {
|
||||
github: {
|
||||
accessToken: accessToken,
|
||||
avatarUrl: profile._json && profile._json.avatar_url ? profile._json.avatar_url : undefined,
|
||||
displayName: profile.displayName,
|
||||
id: profile.id,
|
||||
profileUrl: profile.profileUrl,
|
||||
username: profile.username,
|
||||
}
|
||||
};
|
||||
return done(null, subset);
|
||||
};
|
||||
|
||||
function activeDirectorySubset(iss, sub, profile, accessToken, refreshToken, done) {
|
||||
// CONSIDER: TODO: Hybrid tenant checks.
|
||||
// CONSIDER: Should check for existance of UPN, OID
|
||||
let subset = {
|
||||
azure: {
|
||||
displayName: profile.displayName,
|
||||
oid: profile._json.oid,
|
||||
username: profile._json.upn,
|
||||
token: {
|
||||
access: accessToken,
|
||||
refresh: refreshToken,
|
||||
exp: profile._json.exp,
|
||||
},
|
||||
}
|
||||
};
|
||||
done(null, subset);
|
||||
}
|
||||
|
||||
module.exports = function (app, config) {
|
||||
if (!config.primaryAuthenticationScheme) {
|
||||
config.primaryAuthenticationScheme = 'github';
|
||||
}
|
||||
if (config.primaryAuthenticationScheme !== 'github' && config.primaryAuthenticationScheme !== 'aad') {
|
||||
throw new Error(`Unsupported primary authentication scheme type "${primaryAuthenticationScheme}"`);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// GitHub Passport session setup.
|
||||
// ----------------------------------------------------------------------------
|
||||
// To support persistent login sessions, Passport needs to be able to
|
||||
// serialize users into and deserialize users out of the session. Typically,
|
||||
// this will be as simple as storing the user ID when serializing, and finding
|
||||
// the user by ID when deserializing. However, since this example does not
|
||||
// have a database of user records, the complete GitHub profile is serialized
|
||||
// and deserialized.
|
||||
passport.serializeUser(function(user, done) {
|
||||
done(null, user);
|
||||
});
|
||||
passport.deserializeUser(function(obj, done) {
|
||||
done(null, obj);
|
||||
});
|
||||
var gitHubTokenToSubset = function (accessToken, refreshToken, profile, done) {
|
||||
var subset = {
|
||||
github: {
|
||||
accessToken: accessToken,
|
||||
avatarUrl: profile._json && profile._json.avatar_url ? profile._json.avatar_url : undefined,
|
||||
displayName: profile.displayName,
|
||||
id: profile.id,
|
||||
profileUrl: profile.profileUrl,
|
||||
username: profile.username,
|
||||
}
|
||||
};
|
||||
return done(null, subset);
|
||||
};
|
||||
passport.use(new GitHubStrategy({
|
||||
let githubOptions = {
|
||||
clientID: config.github.clientId,
|
||||
clientSecret: config.github.clientSecret,
|
||||
callbackURL: config.github.callbackUrl,
|
||||
scope: [],
|
||||
userAgent: 'passport-azure-oss-portal-for-github' // CONSIDER: User agent should be configured.
|
||||
}, gitHubTokenToSubset));
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Azure Active Directory Passport session setup.
|
||||
// ----------------------------------------------------------------------------
|
||||
var aadStrategy = new OIDCStrategy({
|
||||
};
|
||||
let githubPassportStrategy = new GitHubStrategy(githubOptions, githubResponseToSubset);
|
||||
let aadStrategy = new OIDCStrategy({
|
||||
callbackURL: config.activeDirectory.redirectUrl,
|
||||
realm: config.activeDirectory.tenantId,
|
||||
clientID: config.activeDirectory.clientId,
|
||||
|
@ -61,21 +79,28 @@ module.exports = function (app, config) {
|
|||
responseType: 'id_token code',
|
||||
responseMode: 'form_post',
|
||||
validateIssuer: true,
|
||||
}, function (iss, sub, profile, accessToken, refreshToken, done) {
|
||||
done(null, profile);
|
||||
});
|
||||
}, activeDirectorySubset);
|
||||
|
||||
// Validate the authorization URL borrowed from the passport-github library
|
||||
if (githubPassportStrategy._oauth2 && githubPassportStrategy._oauth2._authorizeUrl) {
|
||||
app.set('runtime/passport/github/authorizeUrl', githubPassportStrategy._oauth2._authorizeUrl);
|
||||
} else {
|
||||
throw new Error('The GitHub Passport strategy library may have been updated, it no longer contains the expected Authorize URL property within the OAuth2 object.');
|
||||
}
|
||||
|
||||
passport.use('github', githubPassportStrategy);
|
||||
passport.use('azure-active-directory', aadStrategy);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Expanded OAuth-scope GitHub access for org membership writes.
|
||||
// ----------------------------------------------------------------------------
|
||||
var expandedGitHubScopeStrategy = new GitHubStrategy({
|
||||
let expandedGitHubScopeStrategy = new GitHubStrategy({
|
||||
clientID: config.github.clientId,
|
||||
clientSecret: config.github.clientSecret,
|
||||
callbackURL: config.github.callbackUrl + '/increased-scope',
|
||||
scope: ['write:org'],
|
||||
userAgent: 'passport-azure-oss-portal-for-github' // CONSIDER: User agent should be configured.
|
||||
}, gitHubTokenToSubset);
|
||||
}, githubResponseToSubset);
|
||||
|
||||
passport.use('expanded-github-scope', expandedGitHubScopeStrategy);
|
||||
|
||||
|
|
|
@ -3,104 +3,148 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
module.exports = function configurePassport(app, passport) {
|
||||
// ----------------------------------------------------------------------------
|
||||
// passport integration with GitHub
|
||||
// ----------------------------------------------------------------------------
|
||||
app.get('/signin/github', function (req, res) {
|
||||
if (req.session && req.headers && req.headers.referer) {
|
||||
req.session.referer = req.headers.referer;
|
||||
}
|
||||
return res.redirect('/auth/github');
|
||||
});
|
||||
'use strict';
|
||||
|
||||
app.get('/auth/github',
|
||||
passport.authenticate('github'),
|
||||
function (req, res){
|
||||
// The request will be redirected to GitHub for authentication, so this
|
||||
// function will not be called.
|
||||
});
|
||||
const querystring = require('querystring');
|
||||
|
||||
app.get('/auth/github/callback',
|
||||
passport.authenticate('github', { failureRedirect: '/failure/github' }),
|
||||
function (req, res) {
|
||||
var url = '/';
|
||||
if (req.session && req.session.referer) {
|
||||
url = req.session.referer;
|
||||
delete req.session.referer;
|
||||
}
|
||||
res.redirect(url);
|
||||
});
|
||||
module.exports = function configurePassport(app, passport, initialConfig) {
|
||||
// ----------------------------------------------------------------------------
|
||||
// passport integration with GitHub
|
||||
// ----------------------------------------------------------------------------
|
||||
app.get('/signin/github', function (req, res) {
|
||||
if (req.session && req.headers && req.headers.referer) {
|
||||
req.session.referer = req.headers.referer;
|
||||
}
|
||||
return res.redirect('/auth/github');
|
||||
});
|
||||
|
||||
app.get('/signout', function (req, res) {
|
||||
req.logout();
|
||||
res.redirect('https://github.com/logout');
|
||||
});
|
||||
var ghMiddleware = initialConfig.primaryAuthenticationScheme === 'github' ? passport.authenticate('github') : passport.authorize('github');
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Expanded GitHub auth scope routes
|
||||
// ----------------------------------------------------------------------------
|
||||
app.get('/signin/github/increased-scope', function (req, res){
|
||||
if (req.session && req.headers && req.headers.referer) {
|
||||
req.session.referer = req.headers.referer;
|
||||
}
|
||||
return res.redirect('/auth/github/increased-scope');
|
||||
});
|
||||
app.get('/auth/github', ghMiddleware);
|
||||
|
||||
app.get('/auth/github/increased-scope', passport.authorize('expanded-github-scope'));
|
||||
app.get('/auth/github/callback', ghMiddleware, (req, res) => {
|
||||
if (initialConfig.primaryAuthenticationScheme !== 'github') {
|
||||
req.user.github = req.account.github;
|
||||
}
|
||||
var url = '/';
|
||||
if (req.session && req.session.referer) {
|
||||
url = req.session.referer;
|
||||
delete req.session.referer;
|
||||
}
|
||||
res.redirect(url);
|
||||
});
|
||||
|
||||
app.get('/auth/github/callback/increased-scope',
|
||||
passport.authorize('expanded-github-scope'), function (req, res, next) {
|
||||
var account = req.account;
|
||||
var user = req.user;
|
||||
user.github.increasedScope = account;
|
||||
var url = '/';
|
||||
if (req.session && req.session.referer) {
|
||||
url = req.session.referer;
|
||||
delete req.session.referer;
|
||||
}
|
||||
res.redirect(url);
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// passport integration with Azure Active Directory
|
||||
// ----------------------------------------------------------------------------
|
||||
app.get('/auth/azure', passport.authorize('azure-active-directory'));
|
||||
|
||||
app.post('/auth/azure/callback',
|
||||
passport.authorize('azure-active-directory'), function (req, res, next) {
|
||||
var account = req.account;
|
||||
var username = account._json.upn;
|
||||
if (account !== null && username && account.displayName) {
|
||||
req.user.azure = {
|
||||
displayName: account.displayName,
|
||||
oid: account._json.oid,
|
||||
username: username,
|
||||
};
|
||||
var url = '/';
|
||||
if (req.session && req.session.referer) {
|
||||
url = req.session.referer;
|
||||
delete req.session.referer;
|
||||
}
|
||||
return res.redirect(url);
|
||||
} else {
|
||||
return next(new Error('Azure Active Directory authentication failed.'));
|
||||
}
|
||||
if (initialConfig.primaryAuthenticationScheme === 'aad') {
|
||||
app.get('/signin/github/join', (req, res, next) => {
|
||||
res.render('creategithubaccount', {
|
||||
title: 'Create a GitHub account',
|
||||
});
|
||||
|
||||
app.get('/signin/azure', function(req, res){
|
||||
if (req.session && req.headers && req.headers.referer) {
|
||||
if (req.session.referer === undefined) {
|
||||
req.session.referer = req.headers.referer;
|
||||
}
|
||||
}
|
||||
return res.redirect('/auth/azure');
|
||||
});
|
||||
|
||||
app.get('/signout/azure', function(req, res){
|
||||
if (req.user && req.user.azure) {
|
||||
delete req.user.azure;
|
||||
}
|
||||
res.redirect('/');
|
||||
app.get('/auth/github/join', (req, res, next) => {
|
||||
var config = req.app.settings.runtimeConfig;
|
||||
var authorizeRelativeUrl = req.app.settings['runtime/passport/github/authorizeUrl'].replace('https://github.com', '');
|
||||
var joinUrl = 'https://github.com/join?' + querystring.stringify({
|
||||
return_to: `${authorizeRelativeUrl}?` + querystring.stringify({
|
||||
client_id: config.github.clientId,
|
||||
redirect_uri: config.github.callbackUrl,
|
||||
response_type: 'code',
|
||||
scope: '', // TODO: Improve by pulling from object?
|
||||
}),
|
||||
source: 'oauth',
|
||||
});
|
||||
res.redirect(joinUrl);
|
||||
});
|
||||
}
|
||||
|
||||
app.get('/signout', function (req, res) {
|
||||
var config = req.app.settings.runtimeConfig;
|
||||
req.logout();
|
||||
|
||||
if (config.primaryAuthenticationScheme === 'github') {
|
||||
res.redirect('https://github.com/logout');
|
||||
} else {
|
||||
res.render('message', {
|
||||
messageTitle: 'Goodbye!',
|
||||
message: 'You have been signed out.',
|
||||
buttonText: 'Sign In Again',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/signout/github', function (req, res) {
|
||||
if (req.app.settings.runtimeConfig.primaryAuthenticationScheme === 'github') {
|
||||
return res.redirect('/signout');
|
||||
}
|
||||
if (req.user && req.user.github) {
|
||||
delete req.user.github;
|
||||
}
|
||||
var url = req.headers.referer || '/';
|
||||
res.redirect(url);
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Expanded GitHub auth scope routes
|
||||
// ----------------------------------------------------------------------------
|
||||
app.get('/signin/github/increased-scope', function (req, res){
|
||||
if (req.session && req.headers && req.headers.referer) {
|
||||
req.session.referer = req.headers.referer;
|
||||
}
|
||||
return res.redirect('/auth/github/increased-scope');
|
||||
});
|
||||
|
||||
// TODO: xxx
|
||||
app.get('/auth/github/increased-scope', passport.authorize('expanded-github-scope'));
|
||||
|
||||
// TODO: xxx
|
||||
app.get('/auth/github/callback/increased-scope',
|
||||
passport.authorize('expanded-github-scope'), function (req, res, next) {
|
||||
var account = req.account;
|
||||
var user = req.user;
|
||||
user.github.increasedScope = account;
|
||||
var url = '/';
|
||||
if (req.session && req.session.referer) {
|
||||
url = req.session.referer;
|
||||
delete req.session.referer;
|
||||
}
|
||||
res.redirect(url);
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// passport integration with Azure Active Directory
|
||||
// ----------------------------------------------------------------------------
|
||||
var aadMiddleware = initialConfig.primaryAuthenticationScheme === 'github' ? passport.authorize('azure-active-directory') : passport.authenticate('azure-active-directory');
|
||||
|
||||
app.get('/auth/azure', aadMiddleware);
|
||||
|
||||
app.post('/auth/azure/callback', aadMiddleware, (req, res, next) => {
|
||||
if (initialConfig.primaryAuthenticationScheme !== 'aad') {
|
||||
req.user.azure = req.account.azure;
|
||||
}
|
||||
var url = '/';
|
||||
if (req.session && req.session.referer) {
|
||||
url = req.session.referer;
|
||||
delete req.session.referer;
|
||||
}
|
||||
return res.redirect(url);
|
||||
});
|
||||
|
||||
app.get('/signin/azure', function(req, res){
|
||||
if (req.session && req.headers && req.headers.referer) {
|
||||
if (req.session.referer === undefined) {
|
||||
req.session.referer = req.headers.referer;
|
||||
}
|
||||
}
|
||||
return res.redirect('/auth/azure');
|
||||
});
|
||||
|
||||
app.get('/signout/azure', function(req, res){
|
||||
if (req.app.settings.runtimeConfig.primaryAuthenticationScheme === 'aad') {
|
||||
return res.redirect('/signout');
|
||||
}
|
||||
if (req.user && req.user.azure) {
|
||||
delete req.user.azure;
|
||||
}
|
||||
res.redirect('/');
|
||||
});
|
||||
};
|
||||
|
|
40
oss/index.js
40
oss/index.js
|
@ -24,6 +24,10 @@ function OpenSourceUserContext (applicationConfiguration, dataClient, user, redi
|
|||
this.modernUser = function () {
|
||||
return modernUser;
|
||||
};
|
||||
this.createModernUser = function (id, login) {
|
||||
modernUser = new User(this, id);
|
||||
modernUser.login = login;
|
||||
}
|
||||
this.setting = function (name) {
|
||||
return applicationConfiguration[name];
|
||||
};
|
||||
|
@ -53,14 +57,13 @@ function OpenSourceUserContext (applicationConfiguration, dataClient, user, redi
|
|||
github: user && user.github && user.github.id ? user.github.id.toString() : undefined,
|
||||
};
|
||||
if (this.id.github) {
|
||||
modernUser = new User(this, this.id.github);
|
||||
modernUser.login = this.usernames.github;
|
||||
this.createModernUser(this.id.github, this.usernames.github);
|
||||
}
|
||||
this.baseUrl = '/';
|
||||
this.redis = new RedisHelper(this, applicationConfiguration.redis.prefix);
|
||||
this.initializeBasics(function () {
|
||||
this.initializeBasics(function (initError) {
|
||||
if (callback) {
|
||||
return callback(null, self);
|
||||
return callback(initError, self);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -69,11 +72,38 @@ function OpenSourceUserContext (applicationConfiguration, dataClient, user, redi
|
|||
// Populate the user's OSS context object.
|
||||
// ----------------------------------------------------------------------------
|
||||
OpenSourceUserContext.prototype.initializeBasics = function (callback) {
|
||||
var self = this;
|
||||
var requestUser = this.requestUser();
|
||||
if (!userObject && this.setting('primaryAuthenticationScheme') === 'aad' && requestUser.azure && requestUser.azure.username) {
|
||||
return this.dataClient().getUserByAadUpn(requestUser.azure.username, function (findError, userLinks) {
|
||||
if (findError) {
|
||||
// XXX: wrap with a useful message?
|
||||
return callback(findError);
|
||||
}
|
||||
if (userLinks.length === 0) {
|
||||
return callback();
|
||||
}
|
||||
if (userLinks.length > 1) {
|
||||
var tooManyLinksError = new Error(`This account has ${userLinks.length} linked GitHub accounts.`);
|
||||
tooManyLinksError.links = userLinks;
|
||||
tooManyLinksError.tooManyLinks = true;
|
||||
return callback(tooManyLinksError);
|
||||
}
|
||||
var link = userLinks[0];
|
||||
self.usernames.github = link.ghu;
|
||||
self.id.github = link.ghid.toString();
|
||||
self.createModernUser(self.id.github, self.usernames.github);
|
||||
self.entities.link = link;
|
||||
self.modernUser().link = link;
|
||||
// todo: if their AAD name or upn has changed, but oid is still the same... schedule an update!
|
||||
// question: should this.authenticated.github be true or false, since it isn't authenticated yet?
|
||||
callback(null, false);
|
||||
});
|
||||
}
|
||||
var userObject = this.modernUser();
|
||||
if (!userObject) {
|
||||
return callback(new Error("There's a logic bug in the user context object. We cannot continue."));
|
||||
}
|
||||
var self = this;
|
||||
userObject.getLink(function (error, link) {
|
||||
if (error) {
|
||||
return callback(utils.wrapError(error, 'We were not able to retrieve information about any link for your user account at this time.'));
|
||||
|
|
|
@ -129,7 +129,7 @@ h1.huge {
|
|||
|
||||
h2 strong {
|
||||
font-family: "Segoe UI Semibold", Segoe, "Segoe WP", Calibri, Candara, Tahoma, Verdana, Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* custom color button for a more muted appearance */
|
||||
|
@ -184,6 +184,10 @@ h2 strong {
|
|||
border-color: #0078d7;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* wiki editing tools */
|
||||
textarea#editor-body {
|
||||
margin-top: 24px;
|
||||
|
|
|
@ -3,27 +3,31 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
var express = require('express');
|
||||
var router = express.Router();
|
||||
var async = require('async');
|
||||
var moment = require('moment');
|
||||
var utils = require('../utils');
|
||||
var OpenSourceUserContext = require('../oss');
|
||||
|
||||
var linkRoute = require('./link');
|
||||
var linkedUserRoute = require('./index-linked');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const async = require('async');
|
||||
const moment = require('moment');
|
||||
const utils = require('../utils');
|
||||
const OpenSourceUserContext = require('../oss');
|
||||
const linkRoute = require('./link');
|
||||
const linkedUserRoute = require('./index-linked');
|
||||
|
||||
router.use(function (req, res, next) {
|
||||
var config = req.app.settings.runtimeConfig;
|
||||
if (req.isAuthenticated()) {
|
||||
if (req.user && !req.user.github) {
|
||||
// no github info
|
||||
// IF secondary auth,... 1) check for a link
|
||||
// return next(new Error('We do not have your GitHub stuff.'));
|
||||
}
|
||||
if (req.user && req.user.github && !req.user.github.id) {
|
||||
return next(new Error('Invalid GitHub user information provided by GitHub.'));
|
||||
}
|
||||
var config = req.app.settings.runtimeConfig;
|
||||
var dc = req.app.settings.dataclient;
|
||||
var instance = new OpenSourceUserContext(config, dc, req.user, dc.cleanupInTheFuture.redisClient, function (error) {
|
||||
var unused = new OpenSourceUserContext(config, dc, req.user, dc.cleanupInTheFuture.redisClient, function (error, instance) {
|
||||
req.oss = instance;
|
||||
instance.addBreadcrumb(req, 'Organizations');
|
||||
return next();
|
||||
return next(error);
|
||||
});
|
||||
} else {
|
||||
var url = req.originalUrl;
|
||||
|
@ -32,7 +36,8 @@ router.use(function (req, res, next) {
|
|||
req.session.referer = req.originalUrl;
|
||||
}
|
||||
}
|
||||
res.redirect('/auth/github');
|
||||
var authUrl = config.primaryAuthenticationScheme === 'github' ? '/auth/github' : '/auth/azure';
|
||||
res.redirect(authUrl);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -45,16 +50,24 @@ router.get('/', function (req, res, next) {
|
|||
var config = req.app.settings.runtimeConfig;
|
||||
var onboarding = req.query.onboarding !== undefined;
|
||||
var allowCaching = onboarding ? false : true;
|
||||
if (!link && req.user.azure === undefined) {
|
||||
return oss.render(req, res, 'welcome', 'Welcome');
|
||||
}
|
||||
if (!link && req.user.azure && req.user.azure.oid) {
|
||||
return res.redirect('/link');
|
||||
|
||||
if (!link) {
|
||||
if (config.primaryAuthenticationScheme === 'github' && req.user.azure === undefined ||
|
||||
config.primaryAuthenticationScheme === 'aad' && req.user.github === undefined) {
|
||||
return oss.render(req, res, 'welcome', 'Welcome');
|
||||
}
|
||||
if (config.primaryAuthenticationScheme === 'github' && req.user.azure && req.user.azure.oid ||
|
||||
config.primaryAuthenticationScheme === 'aad' && req.user.github && req.user.github.id) {
|
||||
return res.redirect('/link');
|
||||
}
|
||||
return next(new Error('This account is not yet linked, but a workflow error is preventing further progress. Please report this issue. Thanks.'));
|
||||
}
|
||||
|
||||
// They're changing their corporate identity (rare, often just service accounts)
|
||||
if (link && link.aadupn && req.user.azure && req.user.azure.username && req.user.azure.username.toLowerCase() !== link.aadupn.toLowerCase()) {
|
||||
return res.redirect('/link/update');
|
||||
}
|
||||
// TODO: Add similar code for GitHub data, etc.
|
||||
var twoFactorOff = null;
|
||||
var activeOrg = null;
|
||||
async.parallel({
|
||||
|
|
|
@ -58,9 +58,7 @@ router.post('/', function (req, res, next) {
|
|||
if (error) {
|
||||
return next(utils.wrapError(error, 'You were successfully removed from all of your organizations. However, a minor failure happened during a data housecleaning operation. Double check that you are happy with your current membership status on GitHub.com before continuing. Press Report Bug if you would like this handled for sure.'));
|
||||
}
|
||||
delete req.user.azure;
|
||||
req.logout();
|
||||
res.redirect('/');
|
||||
res.redirect('/signout');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
//-
|
||||
//- Copyright (c) Microsoft. All rights reserved.
|
||||
//- Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//-
|
||||
|
||||
extends layout
|
||||
|
||||
block content
|
||||
div.container
|
||||
h2 Create your GitHub account username
|
||||
p.
|
||||
Once you have created your account and verified your e-mail address,
|
||||
please come back to this repository management site to continue your
|
||||
onboarding experience.
|
||||
hr
|
||||
div.row
|
||||
div.col-sm-6.col-md-6.col-lg-6
|
||||
|
||||
a.btn.btn-primary.full-width(href='/auth/github/join')
|
||||
h3 I'm new to GitHub
|
||||
p Let's create a brand new GitHub username
|
||||
|
||||
div.col-sm-6.col-md-6.col-lg-6
|
||||
p.lead Since GitHub is a third-party service, it has its own set of usernames, passwords, multi-factor authentication, and settings.
|
|
@ -84,12 +84,12 @@ html(lang="en")
|
|||
img(alt=user.github.displayName, src=user.github.avatarUrl + '&s=80', style='margin-right:10px;width:30px;height:30px', data-user=user.github.id)
|
||||
a.btn.btn-sm.btn-muted(href='https://github.com/settings/profile', target='_new', title='Click to edit your public GitHub profile')= user.github.username
|
||||
a.btn.btn-sm.btn-muted-more(href='https://github.com/settings/profile', target='_new', title='Click to edit your public GitHub profile')= user.github.displayName || user.github.username
|
||||
a.btn.btn-sm.btn-white(href='/signout', style='margin-left:10px') Sign out
|
||||
a.btn.btn-sm.btn-white(href='/signout', style='margin-left:10px') Sign Out
|
||||
else
|
||||
p
|
||||
small Sign in or create your GitHub.com account to manage your #{config && config.companyName || 'corporate'} open source identity.
|
||||
p
|
||||
a.btn.btn-primary(href='/signin/github') Sign in
|
||||
a.btn.btn-sm.btn-primary(href='/signin/github') Sign in
|
||||
div.col-md-6
|
||||
if user && !error
|
||||
if ossLink
|
||||
|
@ -143,6 +143,9 @@ html(lang="en")
|
|||
h4 Hostname: #{serverName}
|
||||
if config && config.applicationInsights && config.applicationInsights.instrumentationKey
|
||||
h4 AppInsights: Instrumented
|
||||
if config && config.primaryAuthenticationScheme
|
||||
h4
|
||||
| Primary Authentication: #{config.primaryAuthenticationScheme === 'github' ? 'GitHub' : 'Azure Active Directory'}
|
||||
div.col-md-6.col-lg-6(style='background-color:white')
|
||||
if config && config.azureStorage
|
||||
h4
|
||||
|
|
|
@ -14,26 +14,34 @@ block content
|
|||
div.row
|
||||
div.col-md-7.col-lg-7
|
||||
h1 Link your accounts
|
||||
p Linking associates your corporate and social coding accounts to enable self-service GitHub management. It does not alter your GitHub account in any way.
|
||||
p.lead.
|
||||
Enable self-service open source management by linking
|
||||
your corporate & social coding accounts
|
||||
table.table
|
||||
thead
|
||||
tr
|
||||
th GitHub User
|
||||
th #{config.companyName} Identity
|
||||
th GitHub Username
|
||||
th
|
||||
th #{config.companyName} Directory
|
||||
tbody
|
||||
tr
|
||||
td= user.github.displayUsernameTemporary || user.github.username
|
||||
td= user.azure.username
|
||||
- gitAlertClass = config.primaryAuthenticationScheme == 'github' ? '' : 'alert-success'
|
||||
- aadAlertClass = config.primaryAuthenticationScheme == 'aad' ? '' : 'alert-success'
|
||||
td(class=gitAlertClass)= user.github.displayUsernameTemporary || user.github.username
|
||||
td
|
||||
div.text-center
|
||||
i.glyphicon.glyphicon-link
|
||||
td(class=aadAlertClass)= user.azure.username
|
||||
p By continuing, you agree:
|
||||
ul
|
||||
li My GitHub account is controlled exclusively by #{user.azure.username}.
|
||||
li My GitHub password is safe, secure and smart.
|
||||
li I will enable two-factor authentication on my GitHub account and keep it active. I understand that I will lose access if I remove this security protection.
|
||||
li My GitHub account is controlled by #{user.azure.username}
|
||||
li My GitHub password is safe and secure
|
||||
li I will enable two-factor authentication on my GitHub account
|
||||
form(method='post')
|
||||
p(style='margin-top:24px')
|
||||
input.btn.btn-primary(type='submit', value='I Agree')
|
||||
input.btn.btn-lg.btn-primary(type='submit', value='Link')
|
||||
|
|
||||
a.btn.btn-default(href='/signout') Cancel
|
||||
a.btn.btn-lg.btn-default(href='/signout') Cancel
|
||||
hr
|
||||
h3 Your onboarding progress
|
||||
h5
|
||||
|
@ -42,7 +50,7 @@ block content
|
|||
h5.text-primary
|
||||
| Link your identity
|
||||
h5
|
||||
| Join and accept your first organization invite from GitHub
|
||||
| Join your first GitHub organization
|
||||
h5
|
||||
| Multifactor security checkup
|
||||
h5
|
||||
|
@ -58,8 +66,7 @@ block content
|
|||
- var footres = config.corporate.trainingResources.footer
|
||||
if footres
|
||||
// These same resources appear on every single auth page footer, too.
|
||||
h3 Training & Resources
|
||||
p Bookmark these great resources today. These are important resources to grok.
|
||||
h3 Open Source Resources
|
||||
each categoryList, category in footres
|
||||
h5= category
|
||||
ul
|
||||
|
|
|
@ -26,9 +26,10 @@ block content
|
|||
pre= messageOutput
|
||||
|
||||
p
|
||||
a.btn.btn-default(href='/') Home
|
||||
br
|
||||
a.btn.btn-default(href='/')= buttonText || 'Home'
|
||||
|
||||
if config && config.corporate && config.corporate.portalAdministratorEmail
|
||||
p
|
||||
| If you have any questions, please ping
|
||||
a.alert-link(href='mailto:' + config.corporate.portalAdministratorEmail)= config.corporate.portalAdministratorEmail
|
||||
p
|
||||
| If you have any questions, please ping
|
||||
a.alert-link(href='mailto:' + config.corporate.portalAdministratorEmail)= config.corporate.portalAdministratorEmail
|
||||
|
|
|
@ -13,8 +13,7 @@ block content
|
|||
div.container
|
||||
|
||||
h1
|
||||
span.capitalize= org.name
|
||||
|
|
||||
span.capitalize= org.name + ' '
|
||||
small Organization
|
||||
|
||||
div.container
|
||||
|
@ -147,7 +146,7 @@ block content
|
|||
a.btn.btn-default.btn-sm(href=team.org.baseUrl + 'leave') Leave Organization
|
||||
else
|
||||
a.btn.btn-default.btn-sm(href='https://github.com/orgs/' + team.org.name + '/teams/' + team.slug, target='_new')
|
||||
| Open on GitHub
|
||||
| Open on GitHub
|
||||
i.glyphicon.glyphicon-share-alt
|
||||
else
|
||||
//-p You are not currently a member of any GitHub teams that grant you permission to specific repositories. You may be pre-approved to join teams.
|
||||
|
@ -167,7 +166,7 @@ block content
|
|||
h4= orgUser.login
|
||||
p(style='margin-top:18px')
|
||||
a.btn.btn-sm.btn-muted(href='https://github.com/' + org.name, target='_new')
|
||||
| View on GitHub
|
||||
| View on GitHub
|
||||
i.glyphicon.glyphicon-share-alt
|
||||
div.col-md-8.col-lg-8.col-md-offset-1.col-lg-offset-1
|
||||
div.row
|
||||
|
@ -185,16 +184,15 @@ block content
|
|||
h6 On the Web
|
||||
p
|
||||
a(href=orgUser.otherFields.blog, target='_new')
|
||||
= orgUser.otherFields.blog
|
||||
|
|
||||
= orgUser.otherFields.blog + ' '
|
||||
i.glyphicon.glyphicon-share-alt
|
||||
if orgUser.getProfileCreatedDate()
|
||||
h6 Created
|
||||
p
|
||||
p
|
||||
time(datetime=orgUser.getProfileCreatedDate().toISOString())= orgUser.getProfileCreatedDate().toDateString()
|
||||
if orgUser.getProfileCreatedDate()
|
||||
h6 Updated
|
||||
p
|
||||
p
|
||||
time(datetime=orgUser.getProfileUpdatedDate().toISOString())= orgUser.getProfileUpdatedDate().toDateString()
|
||||
hr
|
||||
if org.inner.settings.organizationPurpose
|
||||
|
@ -231,7 +229,7 @@ block content
|
|||
small Remaining Private Repos
|
||||
h2
|
||||
| ∞
|
||||
small Remaining OSS Repos
|
||||
small Remaining Public Repos
|
||||
|
||||
if org.inner.settings.trainingResources
|
||||
- var tr = org.inner.settings.trainingResources
|
||||
|
|
|
@ -15,12 +15,12 @@ block content
|
|||
|
||||
if state == 'pending'
|
||||
|
||||
h1 You've been invited!
|
||||
h1 Action Required: You've been manually invited!
|
||||
|
||||
p.lead We've just had GitHub send you an invitation to <em>#{org.name}</em>.
|
||||
p.lead GitHub has sent an invitation to <em>#{org.name}</em>.
|
||||
p
|
||||
| For security purposes, GitHub requires you to accept the invitation directly on their web site.
|
||||
strong You must come back to this tab after accepting your invitation to continue setting up your open source teams and permissions.
|
||||
| For security purposes, GitHub requires you to accept the invitation directly on their web site.
|
||||
strong You must come back to this tab after accepting your invitation to continue setting up your open source teams and permissions.
|
||||
div.row
|
||||
div.col-md-6.col-lg-6
|
||||
h3 Step 1: Accept your invite from GitHub
|
||||
|
@ -65,19 +65,16 @@ block content
|
|||
a.btn.btn-primary.btn-huge(href='/' + org.name + '/join/express' + (onboarding ? '?onboarding=' + onboarding : ''))
|
||||
| Join #{org.name} now
|
||||
p.
|
||||
Click to authorize this portal to use an additional GitHub API scope,
|
||||
<a href="https://developer.github.com/v3/oauth/#scopes" target="_new"><code>org:write</code></a>
|
||||
to automate the join process. <em>The additional scope will be removed the next time you sign
|
||||
in to this portal.</em>
|
||||
Authorize this site to use the
|
||||
<a href="https://developer.github.com/v3/oauth/#scopes" target="_new"><code>org:write</code></a>
|
||||
scope to automate the join process.
|
||||
//-<em>The additional scope will be removed the next time you sign in to this portal.</em>
|
||||
hr
|
||||
form(method='post')
|
||||
p
|
||||
input.btn.btn-primary.btn-lg(type='submit', value='Join ' + org.name + ' (Manual)')
|
||||
input.btn.btn-default.btn(type='submit', value='Join ' + org.name + ' (Manual)')
|
||||
p.
|
||||
This alternate path does not increase the scope of permissions granted to this portal. After
|
||||
clicking the manual join button, we will 1) send you an invitation from #{org.name}, 2) ask
|
||||
you to accept the invitation over on GitHub.com, and then 3) verify that the invitation was
|
||||
accepted properly.
|
||||
This alternate path will not increase the scope of permissions granted to this site. Instead, the process requires many manual steps:
|
||||
ul
|
||||
li An invitation will be sent from GitHub
|
||||
li On the next page we'll explain how the GitHub invitation works
|
||||
|
@ -87,15 +84,13 @@ block content
|
|||
hr
|
||||
h3 Your onboarding progress
|
||||
h5
|
||||
| Sign in with GitHub & #{config.companyName} IT
|
||||
|
|
||||
| Sign in with GitHub & #{config.companyName}
|
||||
i.glyphicon.glyphicon-ok
|
||||
h5
|
||||
| Link your identity
|
||||
|
|
||||
| Link your identity
|
||||
i.glyphicon.glyphicon-ok
|
||||
h5.text-primary
|
||||
| Join and accept your first organization invite from GitHub
|
||||
| Join your first GitHub organization
|
||||
h5
|
||||
| Multifactor security checkup
|
||||
h5
|
||||
|
@ -113,10 +108,10 @@ block content
|
|||
h4= orgUser.login
|
||||
p(style='margin-top:18px')
|
||||
a.btn.btn-sm.btn-muted(href='https://github.com/' + org.name, target='_new')
|
||||
| View on GitHub
|
||||
| View on GitHub
|
||||
i.glyphicon.glyphicon-share-alt
|
||||
hr
|
||||
|
||||
|
||||
div.row
|
||||
div.col-md-6.col-lg-6
|
||||
if orgUser.company
|
||||
|
@ -132,16 +127,15 @@ block content
|
|||
h6 On the Web
|
||||
p
|
||||
a(href=orgUser.otherFields.blog, target='_new')
|
||||
= orgUser.otherFields.blog
|
||||
|
|
||||
= orgUser.otherFields.blog + ' '
|
||||
i.glyphicon.glyphicon-share-alt
|
||||
if orgUser.getProfileCreatedDate()
|
||||
h6 Created
|
||||
p
|
||||
p
|
||||
time(datetime=orgUser.getProfileCreatedDate().toISOString())= orgUser.getProfileCreatedDate().toDateString()
|
||||
if orgUser.getProfileCreatedDate()
|
||||
h6 Updated
|
||||
p
|
||||
p
|
||||
time(datetime=orgUser.getProfileUpdatedDate().toISOString())= orgUser.getProfileUpdatedDate().toDateString()
|
||||
hr
|
||||
if org.inner.settings.organizationPurpose
|
||||
|
@ -167,7 +161,7 @@ block content
|
|||
h2
|
||||
= orgUser.otherFields.total_private_repos + ' '
|
||||
small Private
|
||||
|
||||
|
||||
hr
|
||||
h6 #{config.companyName} Investment
|
||||
if orgUser.otherFields.plan && orgUser.otherFields.plan.private_repos
|
||||
|
@ -179,4 +173,4 @@ block content
|
|||
small Remaining Private Repos
|
||||
h2
|
||||
| ∞
|
||||
small Remaining OSS Repos
|
||||
small Remaining Public Repos
|
||||
|
|
|
@ -25,26 +25,22 @@ block content
|
|||
a.btn.btn-primary(href=org.baseUrl + (onboarding ? 'membership?onboarding=' + onboarding : 'membership')) Continue
|
||||
|
|
||||
a.btn.btn-default(href='https://github.com/settings/profile', target='_new')
|
||||
| Edit your profile in a new tab
|
||||
| Edit your profile in a new tab
|
||||
i.glyphicon.glyphicon-share-alt
|
||||
if onboarding
|
||||
hr
|
||||
h3 Your onboarding progress
|
||||
h5
|
||||
| Sign in with GitHub & #{config.companyName} IT
|
||||
|
|
||||
| Sign in with GitHub & #{config.companyName}
|
||||
i.glyphicon.glyphicon-ok
|
||||
h5
|
||||
| Link your identity
|
||||
|
|
||||
| Link your identity
|
||||
i.glyphicon.glyphicon-ok
|
||||
h5
|
||||
| Join and accept your first organization invite from GitHub
|
||||
|
|
||||
| Join your first GitHub organization
|
||||
i.glyphicon.glyphicon-ok
|
||||
h5
|
||||
| Multifactor security checkup
|
||||
|
|
||||
| Multifactor security checkup
|
||||
i.glyphicon.glyphicon-ok
|
||||
h5.text-primary
|
||||
| Profile review
|
||||
|
@ -87,10 +83,10 @@ block content
|
|||
span
|
||||
p
|
||||
| Web
|
||||
br
|
||||
br
|
||||
a(href=userProfile.otherFields.blog, target='_new')
|
||||
strong= userProfile.otherFields.blog
|
||||
p(style='margin:16px 0')
|
||||
a.btn.btn-default.btn-sm(href='https://github.com/settings/profile', target='_new')
|
||||
| Edit your profile in a new tab
|
||||
| Edit your profile in a new tab
|
||||
i.glyphicon.glyphicon-share-alt
|
||||
|
|
|
@ -11,7 +11,7 @@ extends layout
|
|||
block content
|
||||
div.container
|
||||
|
||||
h1 Remove your corporate association with #{user.github.displayName || user.github.username}?
|
||||
h1 Unlink #{user.github.username}?
|
||||
|
||||
if orgs && orgs.length && orgs.length > 0
|
||||
p You are currently a member of the following #{config.companyName} organization#{orgs.length == 1 ? '' : 's'} on GitHub:
|
||||
|
@ -21,23 +21,21 @@ block content
|
|||
|
||||
p Please carefully review this page. Removing your corporate association will remove you from all of the organizations listed above.
|
||||
p.
|
||||
<strong>Potential data loss warning:</strong> If you use private repos with your
|
||||
project, and have changes in a private fork that have not yet been committed to the
|
||||
<strong>Potential data loss warning:</strong> If you use private repos with your
|
||||
project, and have changes in a private fork that have not yet been committed to the
|
||||
upstream repo for the org, they will be lost when membership is removed.
|
||||
|
||||
p By continuing, you understand:
|
||||
p Please be very careful and review the following before deciding whether to "unlink" your GitHub account:
|
||||
|
||||
ul
|
||||
li Your GitHub account #{user.github.username} will lose access to #{config.companyName} organizations
|
||||
li Private forks of repos from these orgs, if any, will be removed by GitHub
|
||||
li Work committed in a private fork of a #{config.companyName} org will be lost
|
||||
|
||||
li My GitHub account #{user.github.username} will lose access to any of my organizations
|
||||
li Any private forks of repos from my orgs will be removed by GitHub
|
||||
li Any work done in a private fork of repos from my orgs will be lost. I understand this data loss potential.
|
||||
li Your account will no longer be part of the audit process and is again my own responsibility.
|
||||
|
||||
p If you have any questions about this, please contact your team's GitHub liasons or your corporate legal contact.
|
||||
|
||||
form(method='post', action='/unlink')
|
||||
p
|
||||
input.btn.btn-primary(type='submit', value='I Agree. Remove my corporate access.')
|
||||
|
|
||||
a.btn.btn-default(href='/') Cancel
|
||||
input.btn.btn-lg.btn-primary(type='submit', value='Remove my corporate link')
|
||||
|
|
||||
a.btn.btn-lg.btn-default(href='/') Cancel
|
||||
|
|
|
@ -9,20 +9,45 @@ block content
|
|||
div.container
|
||||
div.row
|
||||
div.col-md-6.col-lg-6.col-sm-6
|
||||
h1 Hi, #{user.github.displayName || user.github.username}
|
||||
h2 #{config.companyName} employees & vendors
|
||||
p.lead To onboard, please authenticate with Active Directory.
|
||||
p
|
||||
a.btn.btn-lg.btn-primary(href='/signin/azure') Sign in to #{config.companyName} IT
|
||||
if config.primaryAuthenticationScheme === 'github'
|
||||
h1 Hi, #{user.github.displayName || user.github.username}
|
||||
h2 #{config.companyName} employees & vendors
|
||||
else if config.primaryAuthenticationScheme === 'aad'
|
||||
h1 Hi, #{user.azure.displayName || user.azure.username}
|
||||
if config.primaryAuthenticationScheme === 'github'
|
||||
p.lead To onboard, please authenticate with Active Directory.
|
||||
p
|
||||
a.btn.btn-lg.btn-primary(href='/signin/azure') Sign in to #{config.companyName}
|
||||
else if config.primaryAuthenticationScheme === 'aad'
|
||||
p.lead Please authenticate with the GitHub account that you want to use for your #{config.companyName} work.
|
||||
div
|
||||
a.btn.btn-primary.btn-huge.full-width(href='/signin/github')
|
||||
h3 I already have a GitHub username
|
||||
p Sign In
|
||||
div
|
||||
a.btn.btn-default.full-width(href='/signin/github/join')
|
||||
h3 I'm new to GitHub
|
||||
p Let's create a brand new GitHub username
|
||||
div.col-md-6.col-lg-6.col-sm-6
|
||||
//-div.alert-gray(style='padding:12px')
|
||||
div(style='padding:12px')
|
||||
//h3 Onboarding
|
||||
p.lead Joining for the first time should take 2-15 minutes
|
||||
p The initial sign-up process should take <strong>2-15 minutes</strong>, depending on whether your GitHub account already has multi-factor authentication enabled.
|
||||
p This onboarding experience will:
|
||||
p.lead Joining should take 2-15 minutes
|
||||
p Onboarding goes pretty quickly, depending on whether you already have a GitHub account and GitHub multi-factor authentication setup.
|
||||
ul
|
||||
li Validate the corporate identity to associate with #{user.github.username}
|
||||
li Step you through joining the GitHub organization
|
||||
if config.primaryAuthenticationScheme === 'github'
|
||||
li Validate the corporate account to link with #{user.github.username}
|
||||
if config.primaryAuthenticationScheme === 'aad'
|
||||
li Validate the GitHub account to link with #{user.azure.username}
|
||||
li Join a #{config.companyName} GitHub organization
|
||||
li Verify and/or configure the two-factor security of your GitHub account
|
||||
li Allow you to request access to any team projects
|
||||
li Allow you to request access to GitHub teams
|
||||
|
||||
if config.primaryAuthenticationScheme === 'aad'
|
||||
hr
|
||||
p.lead One or two GitHub usernames?
|
||||
p.
|
||||
Since Git repositories can be locally configured to mark commits
|
||||
with a name and e-mail address, it's easy to use a single GitHub
|
||||
account for both corporate and other GitHub projects you may
|
||||
work with.
|
||||
p
|
||||
a(href='about:blank', target='_new') Click here for more information
|
||||
|
|
Загрузка…
Ссылка в новой задаче