Skip to content

Commit

Permalink
Add auth api to gateway, authenticated user to DL (#2104)
Browse files Browse the repository at this point in the history
  • Loading branch information
jhoncool authored Feb 5, 2025
1 parent cd54664 commit c7052fe
Show file tree
Hide file tree
Showing 17 changed files with 257 additions and 9 deletions.
24 changes: 23 additions & 1 deletion src/server/components/auth/middlewares/auth/ui-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,39 @@ export const uiAuth = async (req: Request, res: Response, next: NextFunction) =>
},
) as AccessTokenPayload;

const {
responseData: {profile},
} = await gatewayApi.root.auth.getMyUserProfile({
ctx: req.ctx,
headers: {
[AuthHeader.Authorization]: 'Bearer ' + accessToken,
},
requestId: req.id,
authArgs: {},
args: undefined,
});

req.originalContext.set('userId', userId);
req.originalContext.set('user', {
userId,
sessionId,
accessToken,
roles,
profile: {
login: profile.login!,
email: profile.email ?? undefined,
formattedLogin: profile.login!,
displayName:
`${profile.firstName || ''} ${profile.lastName || ''}`.trim() ||
profile.login ||
profile.email ||
userId,
},
});

req.ctx.log('CHECK_ACCESS_TOKEN_SUCCESS');
} catch (err) {
req.ctx.logError('CHECK_ACCESS_TOKEN_ERROR', err);
req.ctx.logError('CHECK_ACCESS_TOKEN_ERROR', isGatewayError(err) ? err.error : err);
onFail(req, res);
return;
}
Expand Down
6 changes: 6 additions & 0 deletions src/server/components/auth/types/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,10 @@ export interface CtxUser {
sessionId: string;
accessToken: string;
roles: `${UserRole}`[];
profile?: {
login: string;
email?: string;
formattedLogin: string;
displayName: string;
};
}
12 changes: 12 additions & 0 deletions src/server/components/layout/opensource-layout-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ export const getOpensourceLayoutConfig: GetLayoutConfig = async (args) => {
user = {...user, ...userInfo};
}

if (isAuthEnabled) {
const authUser = req.ctx.get('user');
iamUserId = authUser?.userId as string;
const profile = authUser?.profile;
user = {
...user,
uid: iamUserId,
roles: authUser?.roles,
...profile,
};
}

const DL: DLGlobalData = {
user,
userSettings,
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ import {actions} from './actions';
export default {
actions,
endpoints: getServiceEndpoints('auth'),
serviceName: 'auth',
serviceName: 'authNotAuthenticated',
};
File renamed without changes.
5 changes: 5 additions & 0 deletions src/shared/schema/auth-schema/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {authSimpleSchema} from './simple-schema';

export const authSchema = {
...authSimpleSchema,
};
File renamed without changes.
102 changes: 102 additions & 0 deletions src/shared/schema/auth/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import {createAction} from '../gateway-utils';
import {defaultParamsSerializer} from '../utils';

import type {SuccessResponse} from './types/common';
import type {
AddUsersRolesArgs,
CreateUserArgs,
CreateUserResponse,
DeleteUserArgs,
GetUserProfileArgs,
GetUserProfileResponse,
GetUsersListArgs,
GetUsersListResponse,
RemoveUsersRolesArgs,
UpdateMyUserPasswordArgs,
UpdateMyUserProfileArgs,
UpdateUserPasswordArgs,
UpdateUserProfileArgs,
UpdateUsersRolesArgs,
} from './types/users';

const PATH_PREFIX = '/v1';

export const actions = {
addUsersRoles: createAction<SuccessResponse, AddUsersRolesArgs>({
method: 'POST',
path: () => `${PATH_PREFIX}/management/users/roles/add`,
params: ({deltas}, headers) => ({body: {deltas}, headers}),
}),
updateUsersRoles: createAction<SuccessResponse, UpdateUsersRolesArgs>({
method: 'POST',
path: () => `${PATH_PREFIX}/management/users/roles/update`,
params: ({deltas}, headers) => ({body: {deltas}, headers}),
}),
removeUsersRoles: createAction<SuccessResponse, RemoveUsersRolesArgs>({
method: 'POST',
path: () => `${PATH_PREFIX}/management/users/roles/remove`,
params: ({deltas}, headers) => ({body: {deltas}, headers}),
}),
createUser: createAction<CreateUserResponse, CreateUserArgs>({
method: 'POST',
path: () => `${PATH_PREFIX}/management/users/create`,
params: ({login, password, email, firstName, lastName, roles}, headers) => ({
body: {login, password, email, firstName, lastName, roles},
headers,
}),
}),
deleteUser: createAction<SuccessResponse, DeleteUserArgs>({
method: 'DELETE',
path: ({userId}) => `${PATH_PREFIX}/management/users/${userId}`,
params: (_args, headers) => ({headers}),
}),
getUserProfile: createAction<GetUserProfileResponse, GetUserProfileArgs>({
method: 'GET',
path: ({userId}) => `${PATH_PREFIX}/management/users/${userId}/profile`,
params: (_args, headers) => ({headers}),
}),
updateUserProfile: createAction<SuccessResponse, UpdateUserProfileArgs>({
method: 'POST',
path: ({userId}) => `${PATH_PREFIX}/management/users/${userId}/profile`,
params: ({email, firstName, lastName}, headers) => ({
body: {email, firstName, lastName},
headers,
}),
}),
updateUserPassword: createAction<SuccessResponse, UpdateUserPasswordArgs>({
method: 'POST',
path: ({userId}) => `${PATH_PREFIX}/management/users/${userId}/password`,
params: ({newPassword}, headers) => ({body: {newPassword}, headers}),
}),

getMyUserProfile: createAction<GetUserProfileResponse, undefined>({
method: 'GET',
path: () => `${PATH_PREFIX}/users/me/profile`,
params: (_args, headers) => ({headers}),
}),
updateMyUserProfile: createAction<SuccessResponse, UpdateMyUserProfileArgs>({
method: 'POST',
path: () => `${PATH_PREFIX}/users/me/profile`,
params: ({email, firstName, lastName}, headers) => ({
body: {email, firstName, lastName},
headers,
}),
}),
updateMyUserPassword: createAction<SuccessResponse, UpdateMyUserPasswordArgs>({
method: 'POST',
path: () => `${PATH_PREFIX}/users/me/password`,
params: ({oldPassword, newPassword}, headers) => ({
body: {oldPassword, newPassword},
headers,
}),
}),
getUsersList: createAction<GetUsersListResponse, GetUsersListArgs>({
method: 'GET',
path: () => `${PATH_PREFIX}/users/list`,
params: ({page, pageSize, filterString, roles}, headers) => ({
query: {page, pageSize, filterString, roles},
headers,
}),
paramsSerializer: defaultParamsSerializer,
}),
};
10 changes: 7 additions & 3 deletions src/shared/schema/auth/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import {authSimpleSchema} from './simple-schema';
import {getServiceEndpoints} from '../../endpoints/schema';

export const authSchema = {
...authSimpleSchema,
import {actions} from './actions';

export default {
actions,
endpoints: getServiceEndpoints('auth'),
serviceName: 'auth',
};
3 changes: 3 additions & 0 deletions src/shared/schema/auth/types/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface SuccessResponse {
done: true;
}
90 changes: 90 additions & 0 deletions src/shared/schema/auth/types/users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import type {UserRole} from '../../../components/auth/constants/role';

export interface AddUsersRolesArgs {
deltas: {
role: `${UserRole}`;
subjectId: string;
}[];
}

export interface RemoveUsersRolesArgs extends AddUsersRolesArgs {}

export interface UpdateUsersRolesArgs {
deltas: {
oldRole: `${UserRole}`;
newRole: `${UserRole}`;
subjectId: string;
}[];
}

export interface CreateUserArgs {
login: string;
password: string;
email?: string;
firstName?: string;
lastName?: string;
roles?: `${UserRole}`[];
}

export interface CreateUserResponse {
userId: string;
}

export interface DeleteUserArgs {
userId: string;
}

export interface GetUserProfileArgs {
userId: string;
}

interface UserProfile {
userId: string;
login: string | null;
email: string | null;
firstName: string | null;
lastName: string | null;
roles: `${UserRole}`[];
}

export interface GetUserProfileResponse {
profile: UserProfile;
}

interface UpdateUserProfile {
email?: string | null;
firstName?: string | null;
lastName?: string | null;
}

export interface UpdateUserProfileArgs extends UpdateUserProfile {
userId: string;
}

export interface UpdateMyUserProfileArgs extends UpdateUserProfile {}

export interface UpdateUserPasswordArgs {
userId: string;
newPassword: string;
}

export interface UpdateMyUserPasswordArgs {
oldPassword: string;
newPassword: string;
}

export interface GetUsersListArgs {
page?: number;
pageSize?: number;
filterString?: string;
roles?: `${UserRole}`[];
}

interface GetUserList extends UserProfile {
providerId: string | null;
}

export interface GetUsersListResponse {
nextPageToken?: string;
users: GetUserList[];
}
2 changes: 1 addition & 1 deletion src/shared/schema/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import mix from './mix';
import {simpleSchema} from './simple-schema';
export {authSchema} from './auth';
export {authSchema} from './auth-schema';

export const schema = {
...simpleSchema,
Expand Down
4 changes: 3 additions & 1 deletion src/shared/schema/simple-schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {getTypedApiFactory} from '@gravity-ui/gateway';

import type {authSimpleSchema} from './auth/simple-schema';
import auth from './auth';
import type {authSimpleSchema} from './auth-schema/simple-schema';
import bi from './bi';
import biConverter from './bi-converter';
import extensions from './extensions';
Expand All @@ -12,6 +13,7 @@ export const simpleSchema = {
bi,
biConverter,
extensions,
auth,
};

export const getTypedApi = getTypedApiFactory<{
Expand Down
2 changes: 2 additions & 0 deletions src/shared/types/common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {RenderParams} from '@gravity-ui/app-layout';
import type {TableSettingsData, Theme, ThemeSettings} from '@gravity-ui/uikit';

import type {UserRole} from '../components/auth/constants/role';
import type {AuthPageSettings} from '../components/auth/types/layout';
import type {AppEnvironment, AppInstallation, DeviceType, Language} from '../constants';
import type {Palette} from '../constants/colors';
Expand Down Expand Up @@ -135,6 +136,7 @@ export interface DLUser extends DLUserAccount {
isGlobalFederationUser?: boolean;
isLocalFederationUser?: boolean;
withNavigation?: boolean;
roles?: `${UserRole}`[];
}

export type MainLayoutConfigData = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ export const AsideHeaderAdapter = ({renderContent, logoIcon}: AsideHeaderAdapter
);
}}
/>
{DL.ZITADEL_ENABLED && (
{(DL.ZITADEL_ENABLED || DL.AUTH_ENABLED) && (
<FooterItem
compact={isCompact}
item={{
Expand Down
2 changes: 1 addition & 1 deletion src/ui/components/UserMenu/UserMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const UserMenu = () => {
<Button
className={b('entry-button')}
title={i18n('label_logout')}
href="/logout"
href={DL.AUTH_ENABLED ? '/auth/logout' : '/logout'}
view="flat-secondary"
>
<Icon data={ArrowRightFromSquare} size={18} />
Expand Down

0 comments on commit c7052fe

Please sign in to comment.