Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes redirect loop bug. #1

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions generators/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,7 @@ module.exports = class extends Generator {
// Boilerplate code
this.fs.copyTpl(
this.templatePath('actions/_auth-actions.js'),
this.destinationPath('src/actions/auth-actions.js'),
{ defaultAllowedUserGroup: this.props.defaultAllowedUserGroup }
this.destinationPath('src/actions/auth-actions.js')
);
this.fs.copy(
this.templatePath('actions/_base-actions.js'),
Expand All @@ -140,7 +139,8 @@ module.exports = class extends Generator {
);
this.fs.copy(
this.templatePath('utils/_constants.js'),
this.destinationPath('src/utils/constants.js')
this.destinationPath('src/utils/constants.js'),
{ defaultAllowedUserGroup: this.props.defaultAllowedUserGroup }
);
// Pages
this.fs.copy(
Expand Down
22 changes: 14 additions & 8 deletions generators/app/templates/_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import LogOutCallbackRoute from './routes/logout-callback-route'
import AuthButton from './components/auth-button'
import DefaultRoute from './routes/default-route'
import { connect } from 'react-redux'
import { onUserAuth, doLogin, doLogout, initLogOut, getUserInfo } from './actions/auth-actions'
import { onUserAuth, doLogin, doLogout, initLogOut, getUserInfo } from 'openstack-uicore-foundation/lib/methods'
import { AjaxLoader } from "openstack-uicore-foundation/lib/components";
import { getBackURL } from "openstack-uicore-foundation/lib/methods";
import T from 'i18n-react';
Expand All @@ -46,6 +46,13 @@ if (language.length > 2) {

T.setTexts(require(`./i18n/${language}.json`));

// move all env var to global scope so ui core has access to this

window.IDP_BASE_URL = process.env['IDP_BASE_URL'];
window.API_BASE_URL = process.env['API_BASE_URL'];
window.OAUTH2_CLIENT_ID = process.env['OAUTH2_CLIENT_ID'];
window.SCOPES = process.env['SCOPES'];
window.ALLOWED_USER_GROUPS = process.env['ALLOWED_USER_GROUPS'];

class App extends React.PureComponent {

Expand All @@ -54,15 +61,15 @@ class App extends React.PureComponent {
}

render() {
let { isLoggedUser, onUserAuth, doLogout, getUserInfo, member, backUrl} = this.props;
let { isLoggedUser, onUserAuth, doLogout, getUserInfo, member, backUrl } = this.props;
let profile_pic = member ? member.pic : '';
return (
<Router history={history}>
<div>
<AjaxLoader show={ this.props.loading } size={ 120 }/>
<OPSessionChecker
clientId={window.clientId}
idpBaseUrl={window.idpBaseUrl}
clientId={window.OAUTH2_CLIENT_ID}
idpBaseUrl={window.IDP_BASE_URL}
/>
<div className="header">
<div className={"header-title " + (isLoggedUser ? '' : 'center')}>
Expand All @@ -71,12 +78,11 @@ class App extends React.PureComponent {
</div>
</div>
<Switch>
<AuthorizedRoute isLoggedUser={isLoggedUser} backUrl={backUrl} path="/app" component={PrimaryLayout} />
<AuthorizationCallbackRoute onUserAuth={onUserAuth} path='/auth/callback' getUserInfo={getUserInfo} />
<LogOutCallbackRoute doLogout={doLogout} path='/auth/logout'/>
<Route path="/logout" render={props => (<p>404 - Not Found</p>)}/>
<Route path="/404" render={props => (<p>404 - Not Found</p>)}/>
<Route path="/error" component={CustomErrorPage}/>
<AuthorizedRoute isLoggedUser={isLoggedUser} backUrl={backUrl} path="/app" component={PrimaryLayout} />
<Route path="/404" render={props => (<p>404 - Not Found</p>)}/>
<LogOutCallbackRoute path='/auth/logout' doLogout={doLogout} />
<DefaultRoute isLoggedUser={isLoggedUser} />
</Switch>
</div>
Expand Down
22 changes: 11 additions & 11 deletions generators/app/templates/_package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@
"less": "^2.7.3",
"less-loader": "^4.1.0",
"moment": "^2.22.0",
"openstack-uicore-foundation": "^1.0.36",
"postcss-loader": "^2.1.3",
"openstack-uicore-foundation": "^1.0.55",
"postcss-loader": "^2.1.6",
"react-dnd": "^2.6.0",
"react-dnd-html5-backend": "^2.6.0",
"react-hot-loader": "^3.1.3",
"react-redux": "^5.0.7",
"react-select": "^1.2.1",
"react-select": "^2.1.2",
"redux": "^3.7.2",
"redux-thunk": "^2.2.0",
"sass-loader": "^6.0.7",
Expand All @@ -55,23 +55,23 @@
"history": "^4.7.2",
"i18n-react": "^0.6.4",
"idtoken-verifier": "^1.2.0",
"immutability-helper": "^2.6.6",
"immutability-helper": "^2.7.1",
"lodash": "^4.17.5",
"moment-timezone": "^0.5.14",
"node-sass": "^4.9.0",
"moment-timezone": "^0.5.21",
"node-sass": "^4.11.0",
"react": "^16.6.3",
"react-bootstrap": "^0.31.5",
"react-breadcrumbs": "^2.1.4",
"react-burger-menu": "^2.5.2",
"react-breadcrumbs": "^2.1.6",
"react-burger-menu": "^2.6.10",
"react-datetime": "^2.15.0",
"react-dom": "^16.3.1",
"react-dom": "^16.4.1",
"react-dropzone": "^4.2.9",
"react-google-maps": "^9.4.5",
"react-router-dom": "^4.2.2",
"react-router-redux": "^5.0.0-alpha.9",
"react-rte": "^0.15.0",
"react-scroll": "^1.7.8",
"redux-persist": "^5.9.1",
"react-scroll": "^1.7.10",
"redux-persist": "^5.10.0",
"uglifyjs-webpack-plugin": "^1.2.7",
"validator": "^9.4.1"
}
Expand Down
4 changes: 0 additions & 4 deletions generators/app/templates/_store.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(reducers, composeEnhancers(applyMiddleware(thunk)));

window.apiBaseUrl = process.env['API_BASE_URL'];
window.clientId = process.env['OAUTH2_CLIENT_ID'];
window.idpBaseUrl= process.env['IDP_BASE_URL'];

const onRehydrateComplete = () => {
// repopulate access token on global access variable
window.accessToken = store.getState().loggedUserState.accessToken;
Expand Down
171 changes: 0 additions & 171 deletions generators/app/templates/actions/_auth-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,174 +11,3 @@
* limitations under the License.
**/

import T from "i18n-react/dist/i18n-react";
import {createAction, getRequest, startLoading, stopLoading, showMessage} from "openstack-uicore-foundation/lib/methods";
import {authErrorHandler, apiBaseUrl} from "./base-actions";
import { AllowedUserGroups } from '../utils/constants';
import URI from "urijs";
import history from '../history'

export const SET_LOGGED_USER = 'SET_LOGGED_USER';
export const LOGOUT_USER = 'LOGOUT_USER';
export const REQUEST_USER_INFO = 'REQUEST_USER_INFO';
export const RECEIVE_USER_INFO = 'RECEIVE_USER_INFO';
export const START_SESSION_STATE_CHECK = 'START_SESSION_STATE_CHECK';
export const END_SESSION_STATE_CHECK = 'END_SESSION_STATE_CHECK';

const NONCE_LEN = 16;

export const getAuthUrl = (backUrl = null, prompt = null, tokenIdHint = null) => {

let oauth2ClientId = process.env['OAUTH2_CLIENT_ID'];
let baseUrl = process.env['IDP_BASE_URL'];
let scopes = process.env['SCOPES'];
let redirectUri =`${window.location.origin}/auth/callback`;

if(backUrl != null)
redirectUri += `?BackUrl=${encodeURI(backUrl)}`;

let nonce = createNonce(NONCE_LEN);
console.log(`created nonce ${nonce}`);
// store nonce to check it later
window.localStorage.setItem('nonce', nonce);
let url = URI(`${baseUrl}/oauth2/auth`);

let query = {
"response_type" : encodeURI("token id_token"),
"scope" : encodeURI(scopes),
"nonce" : nonce,
"client_id" : encodeURI(oauth2ClientId),
"redirect_uri" : encodeURI(redirectUri)
};

if(prompt){
query['prompt'] = prompt;
}

if(prompt){
query['prompt'] = prompt;
}

url = url.query(query);

return url;
}

const getLogoutUrl = (idToken) => {
let baseUrl = process.env['IDP_BASE_URL'];
let url = URI(`${baseUrl}/oauth2/end-session`);
let state = createNonce(NONCE_LEN);
let postLogOutUri = window.location.origin + '/auth/logout';
// store nonce to check it later
window.localStorage.setItem('post_logout_state', state);
/**
* post_logout_redirect_uri should be listed on oauth2 client settings
* on IDP
* "Security Settings" Tab -> Logout Options -> Post Logout Uris
*/
return url.query({
"id_token_hint" : idToken,
"post_logout_redirect_uri" : encodeURI(postLogOutUri),
"state" : state,
});
}

const createNonce = (len) => {
let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let nonce = '';
for(let i = 0; i < len; i++) {
nonce += possible.charAt(Math.floor(Math.random() * possible.length));
}
return nonce;
}

export const doLogin = (backUrl = null) => {
if(backUrl)
console.log(`doLogin - backUrl ${backUrl} `);
let url = getAuthUrl(backUrl);
window.location = url.toString();
}

export const onUserAuth = (accessToken, idToken, sessionState) => (dispatch) => {
dispatch({
type: SET_LOGGED_USER,
payload: {accessToken, idToken, sessionState}
});
}

export const initLogOut = () => {
window.location = getLogoutUrl(window.idToken).toString();
}


export const doLogout = (backUrl) => (dispatch, getState) => {
dispatch({
type: LOGOUT_USER,
payload: {backUrl:backUrl}
});
}

export const getUserInfo = (backUrl) => (dispatch, getState) => {

let { loggedUserState } = getState();
let { accessToken, member } = loggedUserState;
if(member != null){
console.log(`redirecting to ${backUrl}`)
history.push(backUrl);
return;
}

dispatch(startLoading());

return getRequest(
createAction(REQUEST_USER_INFO),
createAction(RECEIVE_USER_INFO),
`${apiBaseUrl}/api/v1/members/me?expand=groups&access_token=${accessToken}`,
authErrorHandler
)({})(dispatch, getState).then(() => {
dispatch(stopLoading());

let { member } = getState().loggedUserState;
if( member == null || member == undefined){
let error_message = {
title: 'ERROR',
html: T.translate("errors.user_not_set"),
type: 'error'
};

dispatch(showMessage( error_message, initLogOut ));

}

let allowedGroups = member.groups.filter((group, idx) => {
return AllowedUserGroups.includes(group.code);
})

if(allowedGroups.length == 0){
let error_message = {
title: 'ERROR',
html: T.translate("errors.user_not_authz"),
type: 'error'
};

dispatch(showMessage( error_message, initLogOut ));
}

history.push(backUrl);
}
);
}

export const onStartSessionStateCheck = () => (dispatch) => {
dispatch({
type: START_SESSION_STATE_CHECK,
payload: {}
});
}

export const onFinishSessionStateCheck = () => (dispatch) => {
dispatch({
type: END_SESSION_STATE_CHECK,
payload: {}
});
}
Loading