packages/core: added custom sign-in provider

This commit is contained in:
Patrik Oldsberg
2020-06-16 17:42:09 +02:00
parent f65f982b1c
commit afc4ba85c8
3 changed files with 115 additions and 1 deletions
+1
View File
@@ -47,6 +47,7 @@
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-helmet": "6.0.0",
"react-hook-form": "^5.7.2",
"react-router": "6.0.0-alpha.5",
"react-router-dom": "6.0.0-alpha.5",
"react-sparklines": "^1.7.0",
@@ -0,0 +1,111 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { useForm } from 'react-hook-form';
import {
Grid,
Typography,
Button,
FormControl,
TextField,
FormHelperText,
makeStyles,
} from '@material-ui/core';
import isEmpty from 'lodash/isEmpty';
import { InfoCard } from '../InfoCard/InfoCard';
import { ProviderComponent, ProviderLoader, SignInProvider } from './types';
import { SignInResult } from '@backstage/core-api';
const ID_TOKEN_REGEX = /^[a-z0-9+/]+\.[a-z0-9+/]+\.[a-z0-9+/]+$/i;
const useFormStyles = makeStyles(theme => ({
form: {
display: 'flex',
flexFlow: 'column nowrap',
},
button: {
alignSelf: 'center',
marginTop: theme.spacing(2),
},
}));
const Component: ProviderComponent = ({ onResult }) => {
const classes = useFormStyles();
const { register, handleSubmit, errors, formState } = useForm<SignInResult>({
mode: 'onChange',
});
return (
<Grid item>
<InfoCard title="Custom User">
<Typography variant="body1">
Enter your own User ID and credentials.
<br />
This selection will not be stored.
</Typography>
<form className={classes.form} onSubmit={handleSubmit(onResult)}>
<FormControl>
<TextField
name="userId"
label="User ID"
margin="normal"
error={Boolean(errors.userId)}
inputRef={register({ required: true })}
/>
{errors.userId && (
<FormHelperText error>{errors.userId.message}</FormHelperText>
)}
</FormControl>
<FormControl>
<TextField
name="idToken"
label="ID Token (optional)"
margin="normal"
autoComplete="off"
error={Boolean(errors.idToken)}
inputRef={register({
required: false,
validate: token =>
!token ||
ID_TOKEN_REGEX.test(token) ||
'Token is not a valid OpenID Connect JWT Token',
})}
/>
{errors.idToken && (
<FormHelperText error>{errors.idToken.message}</FormHelperText>
)}
</FormControl>
<Button
type="submit"
color="primary"
variant="outlined"
className={classes.button}
disabled={!formState?.dirty || !isEmpty(errors)}
>
Continue
</Button>
</form>
</InfoCard>
</Grid>
);
};
// Custom provider doesn't store credentials
const loader: ProviderLoader = async () => undefined;
export const customProvider: SignInProvider = { Component, loader };
@@ -17,6 +17,7 @@
import React, { useLayoutEffect, useState, useMemo, useCallback } from 'react';
import { guestProvider } from './guestProvider';
import { googleProvider } from './googleProvider';
import { customProvider } from './customProvider';
import {
SignInPageProps,
SignInResult,
@@ -29,11 +30,12 @@ import { SignInProvider } from './types';
const PROVIDER_STORAGE_KEY = '@backstage/core:SignInPage:provider';
// Separate list here to avoid exporting internal types
export type SignInProviderId = 'guest' | 'google';
export type SignInProviderId = 'guest' | 'google' | 'custom';
const signInProviders: { [id in SignInProviderId]: SignInProvider } = {
guest: guestProvider,
google: googleProvider,
custom: customProvider,
};
export const useSignInProviders = (