This commit is contained in:
morsh 2017-05-25 17:04:13 +03:00
Родитель 5527dff430
Коммит ae050c0fcc
12 изменённых файлов: 181 добавлений и 89 удалений

Просмотреть файл

@ -1,6 +1,6 @@
{
"main.css": "static/css/main.b2105435.css",
"main.css.map": "static/css/main.b2105435.css.map",
"main.js": "static/js/main.164150ed.js",
"main.js.map": "static/js/main.164150ed.js.map"
"main.js": "static/js/main.0fd897f0.js",
"main.js.map": "static/js/main.0fd897f0.js.map"
}

Просмотреть файл

@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="shortcut icon" href="/favicon.ico"><link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"/><title>React App</title><link href="/static/css/main.b2105435.css" rel="stylesheet"></head><body><div id="root"></div><script type="text/javascript" src="/static/js/main.164150ed.js"></script></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="shortcut icon" href="/favicon.ico"><link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"/><title>React App</title><link href="/static/css/main.b2105435.css" rel="stylesheet"></head><body><div id="root"></div><script type="text/javascript" src="/static/js/main.0fd897f0.js"></script></body></html>

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -12,6 +12,13 @@ const cosmosDBRouter = require('./routes/cosmos-db');
const azureRouter = require('./routes/azure');
const app = express();
app.use((req, res, next) => {
console.log(`Request URL: ${req.url}`);
return next();
});
app.use(cookieParser());
app.use(expressSession({ secret: 'keyboard cat', resave: true, saveUninitialized: false }));
app.use(bodyParser.json());

Просмотреть файл

@ -1,7 +1,7 @@
{
"identityMetadata": "https://login.microsoftonline.com/common/.well-known/openid-configuration",
"validateIssuer": false,
"skipUserProfile": true,
"validateIssuer": true,
"skipUserProfile": false,
"responseType": "id_token code",
"responseMode": "query"
}

Просмотреть файл

@ -279,8 +279,6 @@ router.post('/setup', (req, res) => {
}
var content = (req.body && req.body.json) || '';
console.dir(content);
fs.writeFile(path.join(__dirname, '..', 'config', 'setup.private.json'), content, err => {
if (err) {
console.error(err);

Просмотреть файл

@ -21,8 +21,9 @@ if (fs.existsSync(path.join(__dirname, '..', 'config', 'setup.private.json'))) {
let users = [];
function findByEmail(email, fn) {
for (var i = 0, len = users.length; i < len; i++) {
var user = users[i];
console.info('we are using user: ', user);
let user = users[i];
console.info(`Current logged in user: ${user}`);
if (user.email === email) {
return fn(null, user);
}
@ -66,15 +67,18 @@ function initializePassport() {
skipUserProfile: configAuth.skipUserProfile,
responseType: configAuth.responseType,
responseMode: configAuth.responseMode,
validateIssuer: configAuth.validateIssuer
validateIssuer: configAuth.validateIssuer,
issuer: configSetup.issuer
},
function(iss, sub, profile, accessToken, refreshToken, done) {
console.log(`passport arguments: ${arguments}`);
profile.email = profile.email || profile.upn;
if (!profile.email) {
return done(new Error("No email found"), null);
}
// asynchronous verification, for effect...
process.nextTick(function () {
findByEmail(profile.email, function(err, user) {
@ -141,7 +145,11 @@ router.get('/account', (req, res) => {
function addAuthRoutes() {
router.get('/login',
passport.authenticate('azuread-openidconnect', { failureRedirect: '/login' }),
(req, res, next) => {
console.log('aaa');
return next();
},
passport.authenticate('azuread-openidconnect', { failureRedirect: '/auth/login' }),
function(req, res) {
console.info('Login was called in the Sample');
res.redirect('/');
@ -154,7 +162,7 @@ function addAuthRoutes() {
// provider will redirect the user back to this application at
// /auth/openid/return
router.get('/openid',
passport.authenticate('azuread-openidconnect', { failureRedirect: '/login' }),
passport.authenticate('azuread-openidconnect', { failureRedirect: '/auth/login' }),
function(req, res) {
console.info('Authentication was called in the Sample');
res.redirect('/');
@ -166,7 +174,7 @@ function addAuthRoutes() {
// login page. Otherwise, the primary route function function will be called,
// which, in this example, will redirect the user to the home page.
router.get('/openid/return',
passport.authenticate('azuread-openidconnect', { failureRedirect: '/login' }),
passport.authenticate('azuread-openidconnect', { failureRedirect: '/auth/login' }),
function(req, res) {
console.info('We received a return from AzureAD.');
res.redirect(redirectPath || '/');
@ -179,7 +187,7 @@ function addAuthRoutes() {
// login page. Otherwise, the primary route function function will be called,
// which, in this example, will redirect the user to the home page.
router.post('/openid/return',
passport.authenticate('azuread-openidconnect', { failureRedirect: '/login' }),
passport.authenticate('azuread-openidconnect', { failureRedirect: '/auth/login' }),
function(req, res) {
console.info('We received a return from AzureAD.');
res.redirect(redirectPath || '/');
@ -191,7 +199,10 @@ function addAuthRoutes() {
res.redirect('/');
});
}
if (authEnabled) { addAuthRoutes(); }
if (authEnabled) {
console.log(`Registering auth routes`);
addAuthRoutes();
}
/**
* Adding all authentication middleware on process start.

Просмотреть файл

@ -46,6 +46,7 @@ export default class Home extends React.Component<any, IHomeState> {
redirectUrl: '',
clientID: '',
clientSecret: '',
issuer: '',
loaded: false,
templates: [],

Просмотреть файл

@ -6,11 +6,13 @@ import Button from 'react-md/lib/Buttons/Button';
import Switch from 'react-md/lib/SelectionControls/Switch';
import InfoDrawer from '../common/InfoDrawer';
import { ToastActions } from '../Toast';
import SetupActions from '../../actions/SetupActions';
import SetupStore from '../../stores/SetupStore';
import SetupStore, { ISetupStoreState } from '../../stores/SetupStore';
interface ISetupState extends ISetupConfig {
editedEmail?: string;
validEmail?: boolean;
loaded?: boolean;
}
@ -21,33 +23,44 @@ export default class Setup extends React.Component<any, ISetupState> {
admins: null,
stage: 'none',
enableAuthentication: false,
editedEmail: '',
validEmail: true,
allowHttp: false,
redirectUrl: '',
clientID: '',
clientSecret: '',
loaded: false
loaded: false,
issuer: ''
};
constructor(props: any) {
super(props);
this.checkKeyValue = this.checkKeyValue.bind(this);
this.updateSetupState = this.updateSetupState.bind(this);
this.checkEmailValue = this.checkEmailValue.bind(this);
this.onSave = this.onSave.bind(this);
this.onCancel = this.onCancel.bind(this);
this.onRemoveAdmin = this.onRemoveAdmin.bind(this);
this.onSwitchAllowHttp = this.onSwitchAllowHttp.bind(this);
this.onSwitchAuthenticationEnables = this.onSwitchAuthenticationEnables.bind(this);
this.onFieldChange = this.onFieldChange.bind(this);
this.getAdminArray = this.getAdminArray.bind(this);
}
updateSetupState(state: ISetupStoreState) {
this.setState(state);
}
componentDidMount() {
this.setState(SetupStore.getState());
this.updateSetupState(SetupStore.getState());
SetupActions.load();
SetupStore.listen(state => {
this.setState(state);
});
SetupStore.listen(this.updateSetupState);
}
componentWillUnmount() {
SetupStore.unlisten(this.updateSetupState);
}
validateEmail(email: string): boolean {
@ -56,7 +69,10 @@ export default class Setup extends React.Component<any, ISetupState> {
return re.test(email);
}
checkKeyValue(e: any) {
checkEmailValue(e: any) {
this.setState({ editedEmail: e.target.value })
if (e.key === 'Enter') {
let email = e.target.value;
@ -75,15 +91,60 @@ export default class Setup extends React.Component<any, ISetupState> {
return true;
}
onSave () {
fixRedirectUrl(redirectUrl: string): string {
if (redirectUrl) { return redirectUrl; }
let host = window.location.host;
// On localhost, authentication requests go directly to port 4000
if (host === 'localhost:3000') { host = 'localhost:4000'; }
return window.location.protocol + '//' + host + '/auth/openid/return';
}
getAdminArray(): string[] {
let admins = this.state.admins || [];
if (this.state.editedEmail) {
admins.push(this.state.editedEmail);
}
return admins;
}
onSave(): any {
let admins = this.getAdminArray();
let redirectUrl = this.fixRedirectUrl(this.state.redirectUrl);
if (this.state.enableAuthentication) {
if (!admins || !admins.length) {
return ToastActions.addToast({ text: 'Fill in at least one admin', action: null });
}
if (!redirectUrl) {
return ToastActions.addToast({ text: 'Fill in redirect url', action: null });
}
if (!this.state.issuer) {
return ToastActions.addToast({ text: 'Fill in issuer', action: null });
}
if (!this.state.clientID) {
return ToastActions.addToast({ text: 'Fill in client ID', action: null });
}
if (!this.state.clientSecret) {
return ToastActions.addToast({ text: 'Fill in client secret', action: null });
}
if (!this.state.allowHttp && redirectUrl.startsWith('http:')) {
return ToastActions.addToast({ text: 'Redirect url should start with https or enable http redirects', action: null });
}
}
var setupConfig = {
admins: this.state.admins,
admins: admins,
stage: this.state.stage,
enableAuthentication: this.state.enableAuthentication,
allowHttp: this.state.allowHttp,
redirectUrl: this.state.redirectUrl,
redirectUrl: redirectUrl,
clientID: this.state.clientID,
clientSecret: this.state.clientSecret
clientSecret: this.state.clientSecret,
issuer: this.state.issuer
};
SetupActions.save(setupConfig, () => { window.location.replace('/'); });
}
@ -118,11 +179,10 @@ export default class Setup extends React.Component<any, ISetupState> {
render() {
let { admins, loaded, validEmail, enableAuthentication, redirectUrl, clientID, clientSecret } = this.state;
let { admins, loaded, validEmail, enableAuthentication, redirectUrl, clientID, clientSecret, issuer } = this.state;
if (!redirectUrl) {
redirectUrl = window.location.protocol + '//' + window.location.host + '/auth/openid/return';
}
// Setting default redirect parameter
redirectUrl = this.fixRedirectUrl(redirectUrl);
if (!loaded) {
return null;
@ -143,6 +203,7 @@ export default class Setup extends React.Component<any, ISetupState> {
<div style={{ width: '100%' }}>
<Switch
id="enableAuthentication"
name="enableAuthentication"
label="Enable Authentication"
checked={enableAuthentication}
onChange={this.onSwitchAuthenticationEnables}
@ -171,6 +232,7 @@ export default class Setup extends React.Component<any, ISetupState> {
<div>
<Switch
id="allowHttp"
name="allowHttp"
label="Allow http in authentication responses"
checked={this.state.allowHttp}
onChange={this.onSwitchAllowHttp}
@ -182,11 +244,11 @@ export default class Setup extends React.Component<any, ISetupState> {
id="adminEmail"
label="Administrator Email"
error={!validEmail}
errorText={!validEmail && 'Please enter a valid email address'}
errorText={(!validEmail && 'Please enter a valid email address') || ''}
lineDirection="center"
placeholder="Enter an additional administrator email"
className="md-cell md-cell--bottom"
onKeyDown={this.checkKeyValue}
onKeyDown={this.checkEmailValue}
/>
<TextField
id="redirectUrl"
@ -216,6 +278,15 @@ export default class Setup extends React.Component<any, ISetupState> {
defaultValue={clientSecret}
onChange={this.onFieldChange}
/>
<TextField
id="issuer"
label="Issuer: https://sts.windows.net/{Tenant-ID}/"
lineDirection="center"
placeholder="https://sts.windows.net/{Tenant-ID}/"
className="md-cell md-cell--bottom"
defaultValue={issuer}
onChange={this.onFieldChange}
/>
</div>)
}
<Button flat primary label="Save &amp; Apply" onClick={this.onSave}>save</Button>

Просмотреть файл

@ -5,7 +5,7 @@ import connections from '../data-sources/connections';
import { DataSourceConnector, IDataSourceDictionary } from '../data-sources';
import SetupActions from '../actions/SetupActions';
interface ISetupStoreState extends ISetupConfig {
export interface ISetupStoreState extends ISetupConfig {
loaded: boolean;
saveSuccess: boolean;
}
@ -19,6 +19,7 @@ class SetupStore extends AbstractStoreModel<ISetupStoreState> implements ISetupS
redirectUrl: string;
clientID: string;
clientSecret: string;
issuer: string;
loaded: boolean;
saveSuccess: boolean;
@ -34,6 +35,7 @@ class SetupStore extends AbstractStoreModel<ISetupStoreState> implements ISetupS
this.clientSecret = '';
this.loaded = false;
this.saveSuccess = false;
this.issuer = '';
this.bindListeners({
load: SetupActions.load
@ -48,6 +50,7 @@ class SetupStore extends AbstractStoreModel<ISetupStoreState> implements ISetupS
this.redirectUrl = setupConfig.redirectUrl;
this.clientID = setupConfig.clientID;
this.clientSecret = setupConfig.clientSecret;
this.issuer = setupConfig.issuer;
this.loaded = true;
this.saveSuccess = true;

1
src/types.d.ts поставляемый
Просмотреть файл

@ -155,4 +155,5 @@ interface ISetupConfig {
redirectUrl: string;
clientID: string;
clientSecret: string;
issuer: string;
}