Skip to content

Commit 3b55d4e

Browse files
committed
Experimental login
This requires pulpcore >= 3.60
1 parent c88372f commit 3b55d4e

15 files changed

Lines changed: 152 additions & 247 deletions

File tree

src/api/base.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ export class BaseAPI {
88

99
constructor() {
1010
this.http = axios.create({
11-
// adapter + withCredentials ensures no popup on http basic auth fail
12-
adapter: 'fetch',
13-
withCredentials: false,
14-
15-
// baseURL gets set in PulpAPI
11+
// API_BASE_PATH gets set in pulp.ts.
12+
xsrfCookieName: 'csrftoken',
13+
xsrfHeaderName: 'X-CSRFToken',
14+
// This is what prevents Pulp from sending the "WWW-Authenticat: Basic *" header.
15+
// In turn, firefox will not be asking for a password.
16+
headers: { 'X-Requested-With': 'XMLHttpRequest' },
1617
paramsSerializer: {
1718
serialize: (params) => ParamHelper.getQueryString(params),
1819
},

src/api/pulp-login.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import { PulpAPI } from './pulp';
33
const base = new PulpAPI();
44

55
export const PulpLoginAPI = {
6-
try: (username, password) =>
7-
// roles = any api that will always be there and requires auth
8-
base.http.get(`roles/`, { auth: { username, password } }),
6+
get: () => base.http.get('login/'),
7+
// Here is the place to add more authentication methods for the login...
8+
login: (username: string, password: string) =>
9+
base.http.post('login/', {}, { auth: { username, password } }),
10+
logout: () => base.http.delete('login/'),
911
};

src/api/pulp.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import Cookies from 'js-cookie';
21
import { config } from 'src/ui-config';
32
import { BaseAPI } from './base';
43

@@ -10,16 +9,9 @@ export class PulpAPI extends BaseAPI {
109
super();
1110

1211
this.http.interceptors.request.use((request) => {
13-
if (!request.auth) {
14-
request.auth = JSON.parse(
15-
window.sessionStorage.credentials ||
16-
window.localStorage.credentials ||
17-
'{}',
18-
);
19-
}
20-
12+
// This is kind of delayed, because the settings promise may be evaluated later.
13+
// In search for a better solution.
2114
request.baseURL = config.API_BASE_PATH;
22-
request.headers['X-CSRFToken'] = Cookies.get('csrftoken');
2315

2416
return request;
2517
});

src/app-context.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,32 @@
11
import { type ReactNode, createContext, useContext, useState } from 'react';
22
import { type AlertType } from 'src/components';
3-
import { useUserContext } from './user-context';
43

4+
export interface IAccount {
5+
username?: string;
6+
pulp_href?: string;
7+
prn?: string;
8+
}
59
export interface IAppContextType {
610
alerts: AlertType[];
711
featureFlags; // deprecated
812
hasPermission: (name: string) => boolean;
913
queueAlert: (alert: AlertType) => void;
1014
setAlerts: (alerts: AlertType[]) => void;
1115
settings; // deprecated
12-
user; // deprecated
16+
account: IAccount;
1317
}
1418

1519
export const AppContext = createContext<IAppContextType>(undefined);
1620
export const useAppContext = () => useContext(AppContext);
1721

18-
export const AppContextProvider = ({ children }: { children: ReactNode }) => {
22+
export const AppContextProvider = ({
23+
account,
24+
children,
25+
}: {
26+
account: IAccount;
27+
children: ReactNode;
28+
}) => {
1929
const [alerts, setAlerts] = useState<AlertType[]>([]);
20-
const { credentials } = useUserContext();
2130

2231
// hub compat for now
2332
const featureFlags = {
@@ -49,14 +58,7 @@ export const AppContextProvider = ({ children }: { children: ReactNode }) => {
4958
queueAlert,
5059
setAlerts,
5160
settings,
52-
// FIXME: hack
53-
user: credentials
54-
? {
55-
username: credentials.username,
56-
groups: [],
57-
model_permissions: {},
58-
}
59-
: null,
61+
account,
6062
}}
6163
>
6264
{children}

src/app-routes.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import {
3737
FileRepositoryList,
3838
GroupDetail,
3939
GroupList,
40-
LoginPage,
4140
MultiSearch,
4241
MyImports,
4342
MyNamespaces,
@@ -59,7 +58,7 @@ import {
5958
import { Paths, formatPath } from 'src/paths';
6059
import { config } from 'src/ui-config';
6160
import { loginURL } from 'src/utilities';
62-
import { useUserContext } from './user-context';
61+
import { useAppContext } from './app-context';
6362

6463
interface IRouteConfig {
6564
beta?: boolean;
@@ -234,11 +233,6 @@ const routes: IRouteConfig[] = [
234233
path: Paths.ansible.namespace.mine,
235234
beta: true,
236235
},
237-
{
238-
component: LoginPage,
239-
path: Paths.meta.login,
240-
noAuth: true,
241-
},
242236
{
243237
component: CollectionDocs,
244238
path: Paths.ansible.collection.docs_page,
@@ -322,10 +316,12 @@ const AuthHandler = ({
322316
noAuth,
323317
path,
324318
}: IRouteConfig) => {
325-
const { credentials } = useUserContext();
319+
const {
320+
account: { username },
321+
} = useAppContext();
326322
const { pathname } = useLocation();
327323

328-
if (!credentials && !noAuth) {
324+
if (!username && !noAuth) {
329325
// NOTE: also update LoginLink when changing this
330326
if (config.UI_EXTERNAL_LOGIN_URI) {
331327
window.location.replace(loginURL(pathname));
@@ -401,6 +397,11 @@ export const dataRoutes = [
401397
index: true,
402398
loader: () => redirect(formatPath(Paths.core.status)),
403399
},
400+
{
401+
path: 'login',
402+
id: 'login',
403+
lazy: () => import('src/routes/login').then((m) => convert(m)),
404+
},
404405
...appRoutes(),
405406
// "No matching route" is not handled by the error boundary.
406407
{ path: '*', element: <NotFound /> },

src/components/delete-user-modal.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { t } from '@lingui/core/macro';
22
import { Trans } from '@lingui/react/macro';
33
import { useState } from 'react';
44
import { UserAPI, type UserType } from 'src/api';
5+
import { useAppContext } from 'src/app-context';
56
import { DeleteModal } from 'src/components';
6-
import { useUserContext } from 'src/user-context';
77
import { jsxErrorMessage, mapErrorMessages } from 'src/utilities';
88

99
interface IProps {
@@ -20,7 +20,9 @@ export const DeleteUserModal = ({
2020
user,
2121
}: IProps) => {
2222
const [waiting, setWaiting] = useState(false);
23-
const { credentials } = useUserContext();
23+
const {
24+
account: { username },
25+
} = useAppContext();
2426

2527
if (!user || !isOpen) {
2628
return null;
@@ -30,11 +32,11 @@ export const DeleteUserModal = ({
3032
<DeleteModal
3133
cancelAction={() => closeModal(false)}
3234
deleteAction={() => deleteUser()}
33-
isDisabled={waiting || user.username === credentials.username}
35+
isDisabled={waiting || user.username === username}
3436
spinner={waiting}
3537
title={t`Delete user?`}
3638
>
37-
{user.username === credentials.username ? (
39+
{user.username === username ? (
3840
t`Deleting yourself is not allowed.`
3941
) : (
4042
<Trans>

src/containers/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ export { default as FileRepositoryEdit } from './file-repository/edit';
2828
export { default as FileRepositoryList } from './file-repository/list';
2929
export { default as GroupDetail } from './group-management/group-detail';
3030
export { default as GroupList } from './group-management/group-list';
31-
export { default as LoginPage } from './login/login';
3231
export { default as MyImports } from './my-imports/my-imports';
3332
export { default as NamespaceDetail } from './namespace-detail/namespace-detail';
3433
export { default as MyNamespaces } from './namespace-list/my-namespaces';

src/containers/login/login.tsx

Lines changed: 0 additions & 89 deletions
This file was deleted.

src/containers/settings/user-profile.tsx

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { t } from '@lingui/core/macro';
22
import { Button } from '@patternfly/react-core';
33
import { useEffect, useState } from 'react';
44
import { UserAPI, type UserType } from 'src/api';
5+
import { useAppContext } from 'src/app-context';
56
import {
67
AlertList,
78
type AlertType,
@@ -10,7 +11,6 @@ import {
1011
UserFormPage,
1112
closeAlert,
1213
} from 'src/components';
13-
import { useUserContext } from 'src/user-context';
1414
import {
1515
type ErrorMessagesType,
1616
type RouteProps,
@@ -27,10 +27,8 @@ function UserProfile(_props: RouteProps) {
2727
const [user, setUser] = useState<UserType>();
2828

2929
const {
30-
credentials: { username },
31-
updateUsername,
32-
updatePassword,
33-
} = useUserContext();
30+
account: { username },
31+
} = useAppContext();
3432

3533
const addAlert = (alert: AlertType) => {
3634
setAlerts([...alerts, alert]);
@@ -65,14 +63,6 @@ function UserProfile(_props: RouteProps) {
6563
variant: 'success',
6664
title: t`Saved changes to user "${username}".`,
6765
});
68-
69-
// update saved credentials when password of logged user is changed
70-
if (user.password) {
71-
updatePassword(user.password);
72-
}
73-
if (username !== user.username) {
74-
updateUsername(user.username);
75-
}
7666
})
7767
.catch((err) => setErrorMessages(mapErrorMessages(err)));
7868

src/containers/user-management/user-edit.tsx

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
UserFormPage,
1010
} from 'src/components';
1111
import { Paths, formatPath } from 'src/paths';
12-
import { useUserContext } from 'src/user-context';
1312
import {
1413
type ErrorMessagesType,
1514
type RouteProps,
@@ -19,23 +18,15 @@ import {
1918

2019
function UserEdit(props: RouteProps) {
2120
const [errorMessages, setErrorMessages] = useState<ErrorMessagesType>({});
22-
const [initialState, setInitialState] = useState<UserType>();
2321
const [redirect, setRedirect] = useState<string>();
2422
const [unauthorized, setUnauthorized] = useState<boolean>(false);
2523
const [user, setUser] = useState<UserType>();
2624

27-
const {
28-
credentials: { username },
29-
updateUsername,
30-
updatePassword,
31-
} = useUserContext();
32-
3325
const id = props.routeParams.user_id;
3426
useEffect(() => {
3527
UserAPI.get(id)
3628
.then(({ data: result }) => {
3729
const extendedResult = { ...result, password: '' };
38-
setInitialState({ ...extendedResult });
3930
setUser(extendedResult);
4031
setUnauthorized(false);
4132
})
@@ -45,14 +36,6 @@ function UserEdit(props: RouteProps) {
4536
const saveUser = () =>
4637
UserAPI.saveUser(user)
4738
.then(() => {
48-
// update saved credentials when password of logged user is changed
49-
if (initialState.username === username && user.password) {
50-
updatePassword(user.password);
51-
}
52-
if (initialState.username === username && username !== user.username) {
53-
updateUsername(user.username);
54-
}
55-
5639
setRedirect(formatPath(Paths.core.user.list));
5740
})
5841
.catch((err) => setErrorMessages(mapErrorMessages(err)));

0 commit comments

Comments
 (0)