Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React, { Component } from 'react';
- import PropTypes from 'prop-types';
- import * as uuid from 'uuid';
- import Toast from 'react-native-simple-toast';
- import { Dimensions, Modal, SafeAreaView, Text, TextInput, TouchableOpacity, View, WebView, Alert } from 'react-native';
- import { CONST } from './azureAD';
- import PreloaderScreen from '../../components/PreloaderScreen';
- const loginUrl =
- 'https://login.microsoftonline.com/<tenant id>/oauth2/authorize';
- export default class ADLoginView extends Component {
- static propTypes = {
- context: PropTypes.object.isRequired,
- style: PropTypes.object.isRequired,
- onSuccess: PropTypes.func.isRequired,
- onBackpress: PropTypes.func.isRequired,
- authority_host: PropTypes.string,
- needLogout: PropTypes.bool,
- };
- static defaultProps = {
- authority_host: loginUrl,
- needLogout: false,
- };
- constructor(props) {
- super(props);
- this._handleADToken = this._handleADToken.bind(this);
- const { context, needLogout } = props;
- const { tenant } = context.getConfig();
- this._needRedirect = needLogout || false;
- this.state = {
- page: this._getLoginUrl(tenant || 'common'),
- visible: true,
- color: '#000',
- authenticating: false,
- username: null,
- password: null,
- lastPage: null,
- };
- this._lock = false;
- }
- componentWillReceiveProps(nextProps) {
- if (!this.props.needLogout && nextProps.needLogout) {
- const { context } = this.props;
- const { tenant } = context.getConfig();
- this._needRedirect = nextProps.needLogout || false;
- this.setState({
- page: this._getLoginUrl(tenant || 'common'),
- visible: true,
- });
- }
- }
- componentWillUpdate(nextProps, nextState) {
- if (
- this.state.visible === nextState.visible &&
- this.state.page === nextState.page
- ) {
- return false;
- }
- return true;
- }
- _needRedirect;
- _onTokenGranted;
- _lock;
- _accessToken;
- /**
- * Get authority host URI,
- * @param {string} tenant Custom tenant ID, this filed is optional, default
- * values is `common`.
- * @return {string} The Authority host URI.
- */
- _getLoginUrl(tenant) {
- const authUrl = String(this.props.authority_host || loginUrl).replace(
- '<tenant id>',
- tenant,
- );
- const context = this.props.context || null;
- // eslint-disable-next-line
- const { prompt, redirect_uri, client_id } = context.getConfig();
- if (context !== null) {
- let result = [
- `${authUrl}?response_type=code`,
- `client_id=${client_id}`, // eslint-disable-line
- `&nonce=rnad-${Date.now()}`,
- ].join('&');
- if (this._needRedirect) {
- result = `https://login.microsoftonline.com/${
- this.props.context.getConfig().tenant
- }/oauth2/logout?post_logout_redirect_uri=http%3A%2F%2Flocalhost%3A3000%2F:165`;
- }
- return result;
- }
- throw new Error('AD context should not be null/undefined.');
- }
- /**
- * An interceptor for handling webview url change, when it detects possible
- * authorization code in url, it will triggers authentication flow.
- * @param {object} e Navigation state change event object.
- */
- _handleADToken(e) {
- // eslint-disable-next-line
- let code = /((\?|\&)code\=)[^\&]+/.exec(e.url);
- const { authenticating } = this.state;
- const authFlow =
- e.url.includes('sts.warnerbros.com') && !e.url.includes('@');
- this.lastPage = e.url;
- console.log(e);
- Alert.alert('Redirect', JSON.stringify(e, null, 2));
- if (authFlow && !e.loading && !authenticating) {
- console.log('Starting auth flow');
- this.setState({ authenticating: true });
- }
- if (this._needRedirect) {
- return true;
- }
- if (code !== null) {
- this.setState(() => ({ visible: false, color: '#FFF' }));
- // eslint-disable-next-line
- code = String(code[0]).replace(/(\?|\&)?code\=/, "");
- this._getResourceAccessToken(code).catch(err => {
- this.setState(() => ({ color: 'red' }));
- this.props.onBackpress();
- Toast.show(err.message ? err.message : err);
- });
- return true;
- }
- return true;
- }
- /**
- * Get access token for each resoureces
- * @param {string} code The authorization code from `onNavigationStateChange`
- * callback.
- * @return {Promise<void>}
- */
- _getResourceAccessToken(code) {
- const { context } = this.props;
- if (!context) {
- throw new Error(
- 'property `context` of ADLoginView should not be null/undefined',
- );
- }
- const adConfig = this.props.context.getConfig();
- // eslint-disable-next-line
- let { client_id, resources } = adConfig;
- // Transform resource string to array
- if (typeof resources === 'string') {
- resources = [resources];
- } else if (Array.isArray(resources)) {
- resources = resources.length === 0 ? null : resources;
- }
- let promises = [];
- const config = { client_id, code, resource: 'common' };
- if (resources === null || resources === undefined) {
- promises.push(
- context.grantAccessToken(CONST.GRANT_TYPE.AUTHORIZATION_CODE, config),
- );
- } else {
- promises = resources.map(rcs => {
- const cfg = Object.assign({}, config, { resource: rcs });
- return context.grantAccessToken(
- CONST.GRANT_TYPE.AUTHORIZATION_CODE,
- cfg,
- );
- });
- }
- return Promise.all(promises)
- .then(() => {
- if (!this.props.context) {
- throw new Error(
- 'value of property `context` is invalid=',
- this.props.context,
- );
- }
- // trigger loggined finished event
- if (this.props.context !== null) {
- this.setState(() => ({ color: '#FFF' }));
- this.props.onSuccess(context.getCredentials());
- }
- })
- .catch(err => {
- throw new Error(err);
- });
- }
- render() {
- // Fix visibility problem on Android webview
- const js = `document.getElementsByTagName('body')[0].style.height = '${
- Dimensions.get('window').height
- }px';`;
- if (!this.state.visible) {
- return (
- <PreloaderScreen
- color={this.state.color}
- key={uuid.v4()}
- style={{
- position: 'absolute',
- left: 0,
- right: 0,
- bottom: 0,
- top: 0,
- }}
- />
- );
- }
- return (
- <SafeAreaView
- style={{
- flex: 2,
- width: '100%',
- backgroundColor: '#262626',
- }}
- >
- <View style={{ flex: 1 }}>
- <WebView
- automaticallyAdjustContentInsets={false}
- ref={ref => (this.webview = ref)}
- style={[
- this.props.style,
- {
- flex: 1,
- alignSelf: 'stretch',
- width: Dimensions.get('window').width,
- height: Dimensions.get('window').height,
- },
- ]}
- source={{ uri: this.state.page }}
- javaScriptEnabled
- domStorageEnabled
- onLoadEnd={() => {
- if (this._needRedirect) {
- this._needRedirect = false;
- const tenant =
- this.props.context.getConfig().tenant || 'common';
- this.setState({ page: this._getLoginUrl(tenant) });
- }
- }}
- decelerationRate="normal"
- javaScriptEnabledAndroid
- onNavigationStateChange={this._handleADToken}
- onShouldStartLoadWithRequest={() => true}
- startInLoadingState
- injectedJavaScript={js}
- scalesPageToFit
- onError={() => this.props.onBackpress()}
- />
- <Modal
- animationType="slide"
- transparent={false}
- visible={this.state.authenticating}
- >
- <View style={{ flex: 1, marginTop: 22, padding: 50 }}>
- <Text
- style={{
- fontSize: 25,
- color: 'black',
- textAlign: 'center',
- marginBottom: 22,
- }}
- >
- Login again lol
- </Text>
- <TextInput
- style={{ height: 50 }}
- placeholder="Username"
- onChangeText={username => this.setState({ username })}
- value={this.state.username}
- />
- <TextInput
- style={{ height: 50 }}
- placeholder="Password"
- secureTextEntry
- onChangeText={password => this.setState({ password })}
- value={this.state.password}
- />
- <TouchableOpacity
- onPress={() => {
- this.setState({ authenticating: false });
- console.log('Starting injecting JS');
- let url = this.lastPage;
- const username = this.state.username;
- const password = this.state.password;
- if (url.indexOf('@') === -1){
- url = url.replace('://','://' + username + ":" + password + "@")
- }
- console.log('Setting URL to', url);
- this.setState({ page: url });
- this.webview.reload();
- }}
- >
- <Text
- style={{
- fontSize: 25,
- color: 'black',
- textAlign: 'center',
- padding: 20,
- }}
- >
- SUBMIT
- </Text>
- </TouchableOpacity>
- </View>
- </Modal>
- </View>
- </SafeAreaView>
- );
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement