Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
580122f
feat: introduce ims authentication
dzehnder Mar 27, 2025
9c937c3
chore: api-doc
solaris007 Mar 28, 2025
a9dafc7
fix: adding mock auth context to tests
dzehnder Mar 28, 2025
40abe31
fix: PR review
dzehnder Mar 28, 2025
fd2151d
fix: adding auth to suggestions
dzehnder Mar 28, 2025
db0b14f
fix: userHasSubService for auto-fix
dzehnder Mar 31, 2025
30dcd3f
fix: introduce access control util
dzehnder Mar 31, 2025
ced6bf2
feat: adding ims auth to audits
dzehnder Mar 31, 2025
1ab7191
Merge branch 'main' into feat-ims-login
solaris007 Apr 1, 2025
aef12e9
feat: adding ims auth to audits
dzehnder Apr 2, 2025
c91a9d1
Merge branch 'refs/heads/main' into feat-ims-login
dzehnder Apr 3, 2025
bbf6596
fix: package lock
dzehnder Apr 3, 2025
80e7e40
Merge branch 'feat-ims-login' of github.com:adobe/spacecat-api-servic…
dzehnder Apr 3, 2025
db27635
fix: tmp fix failing tests
dzehnder Apr 3, 2025
46e4677
Merge branch 'refs/heads/main' into feat-ims-login
dzehnder Apr 4, 2025
ef37039
fix: access control returns admin access if not jwt
dzehnder Apr 4, 2025
92de5a8
fix: adding access control to all endpoints
dzehnder Apr 7, 2025
1d12d20
fix: brands test
dzehnder Apr 7, 2025
b58e8fc
fix: slack bot anonymous calls
dzehnder Apr 9, 2025
868115f
fix: tests not having path info
dzehnder Apr 9, 2025
0d434bb
fix: update http utils
dzehnder Apr 14, 2025
6b773c7
fix: failing tests
dzehnder Apr 15, 2025
c611f33
Merge branch 'refs/heads/main' into feat-ims-login
dzehnder Apr 17, 2025
8f241b3
fix: update package lock
dzehnder Apr 17, 2025
7b8efcf
fix: update http utils
dzehnder Apr 17, 2025
c6a4a1d
fix: update http utils
dzehnder Apr 17, 2025
5a6c840
fix: update http utils
dzehnder Apr 17, 2025
9bfe75d
fix: increasing test coverage
ravverma Apr 25, 2025
0915359
fix: test coverage to 100
dzehnder Apr 28, 2025
a93f4b5
Merge branch 'main' into feat-ims-login
dzehnder Apr 28, 2025
1ff9c3c
fix: merge and adjust new endpoint
dzehnder Apr 28, 2025
1e73262
fix: adding 403 api doc
dzehnder May 7, 2025
e6e8ebd
fix: adding 403 api doc
dzehnder May 7, 2025
1358365
Merge branch 'main' into feat-ims-login
dzehnder May 7, 2025
f529962
fix: update http utils
dzehnder May 7, 2025
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
20 changes: 16 additions & 4 deletions docs/index.html

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions docs/openapi/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ paths:
$ref: './auth-api.yaml#/google-auth'
/auth/google/{siteId}/status:
$ref: './auth-api.yaml#/google-auth-status'
/auth/login:
$ref: './auth-api.yaml#/login'
/configurations:
$ref: './configurations-api.yaml#/configurations'
/configurations/latest:
Expand Down
43 changes: 43 additions & 0 deletions docs/openapi/auth-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,46 @@ google-auth-status:
'500':
$ref: './responses.yaml#/500'
security: []
login:
post:
summary: Authenticate with access token
description: |
Authenticates a user using an IMS access token and returns session information.
operationId: login
tags:
- auth
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- accessToken
properties:
accessToken:
type: string
description: The access token to authenticate with
responses:
'200':
description: Login successful
content:
application/json:
schema:
type: object
properties:
sessionToken:
type: string
description: A JWT token signed by the service containing the user profile and tenants.
'401':
Comment thread
dzehnder marked this conversation as resolved.
description: Authentication failed
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error message
example: "Invalid access token"
security: [] # No security required for login endpoint
58 changes: 29 additions & 29 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@
"@adobe/helix-shared-wrap": "2.0.2",
"@adobe/helix-status": "10.1.5",
"@adobe/helix-universal-logger": "3.0.24",
"@adobe/spacecat-shared-brand-client": "1.0.2",
"@adobe/spacecat-shared-data-access": "2.13.1",
"@adobe/spacecat-shared-gpt-client": "1.5.4",
"@adobe/spacecat-shared-http-utils": "1.9.12",
"@adobe/spacecat-shared-http-utils": "https://gitpkg.vercel.app/adobe/spacecat-shared/packages/spacecat-shared-http-utils?fix-auth-handling",
"@adobe/spacecat-shared-ims-client": "1.5.9",
"@adobe/spacecat-shared-rum-api-client": "2.22.0",
"@adobe/spacecat-shared-brand-client": "1.0.2",
"@adobe/spacecat-shared-slack-client": "1.5.8",
"@adobe/spacecat-shared-utils": "1.35.0",
"@aws-sdk/client-s3": "3.758.0",
Expand Down Expand Up @@ -105,7 +105,7 @@
"@adobe/helix-universal-devserver": "1.1.93",
"@adobe/semantic-release-coralogix": "1.1.35",
"@adobe/semantic-release-skms-cmr": "1.1.5",
"@redocly/cli": "1.33.0",
"@redocly/cli": "1.34.0",
"@semantic-release/changelog": "6.0.3",
"@semantic-release/exec": "7.0.3",
"@semantic-release/git": "10.0.1",
Expand Down
17 changes: 15 additions & 2 deletions src/controllers/organizations.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
badRequest,
noContent,
notFound,
ok,
ok, forbidden,
} from '@adobe/spacecat-shared-http-utils';
import {
hasText,
Expand All @@ -26,6 +26,7 @@ import {

import { OrganizationDto } from '../dto/organization.js';
import { SiteDto } from '../dto/site.js';
import { isAdmin, userBelongsToOrg } from '../utils/authentication.js';

/**
* Organizations controller. Provides methods to create, read, update and delete organizations.
Expand All @@ -51,6 +52,10 @@ function OrganizationsController(dataAccess, env) {
* @return {Promise<Response>} Organization response.
*/
const createOrganization = async (context) => {
if (!isAdmin(context)) {
return forbidden('Only admins can create new Organizations');
}

try {
const organization = await Organization.create(context.data);
return createResponse(OrganizationDto.toJSON(organization), 201);
Expand All @@ -63,7 +68,11 @@ function OrganizationsController(dataAccess, env) {
* Gets all organizations.
* @returns {Promise<Response>} Array of organizations response.
*/
const getAll = async () => {
const getAll = async (context) => {
if (!isAdmin(context)) {
return forbidden('Only admins can view all Organizations');
}

const organizations = (await Organization.all())
.map((organization) => OrganizationDto.toJSON(organization));
return ok(organizations);
Expand All @@ -76,6 +85,10 @@ function OrganizationsController(dataAccess, env) {
* @throws {Error} If organization ID is not provided.
*/
const getByID = async (context) => {
if (!userBelongsToOrg(context)) {
return forbidden('Only users belonging to the organization can view it');
}

const organizationId = context.params?.organizationId;

if (!isValidUUID(organizationId)) {
Expand Down
6 changes: 5 additions & 1 deletion src/controllers/suggestions.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/
import {
badRequest,
createResponse,
createResponse, forbidden,
noContent,
notFound,
ok,
Expand All @@ -27,6 +27,7 @@ import {
import { ValidationError, Suggestion as SuggestionModel } from '@adobe/spacecat-shared-data-access';
import { SuggestionDto } from '../dto/suggestion.js';
import { sendAutofixMessage } from '../support/utils.js';
import { userHasSubService } from '../utils/authentication.js';

/**
* Suggestions controller.
Expand Down Expand Up @@ -388,6 +389,9 @@ function SuggestionsController(dataAccess, sqs, env) {
return createResponse(fullResponse, 207);
};
const autofixSuggestions = async (context) => {
if (!userHasSubService(context, 'autofix')) {
return forbidden('User does not have autofix sub-service');
}
const siteId = context.params?.siteId;
const opportunityId = context.params?.opportunityId;

Expand Down
5 changes: 4 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
LegacyApiKeyHandler,
ScopedApiKeyHandler,
AdobeImsHandler,
JwtHandler,
} from '@adobe/spacecat-shared-http-utils';
import { imsClientWrapper } from '@adobe/spacecat-shared-ims-client';
import {
Expand Down Expand Up @@ -136,7 +137,9 @@ async function run(request, context) {
const { WORKSPACE_EXTERNAL } = SLACK_TARGETS;

export const main = wrap(run)
.with(authWrapper, { authHandlers: [LegacyApiKeyHandler, ScopedApiKeyHandler, AdobeImsHandler] })
.with(authWrapper, {
authHandlers: [LegacyApiKeyHandler, ScopedApiKeyHandler, AdobeImsHandler, JwtHandler],
})
.with(dataAccess)
.with(bodyData)
.with(multipartFormData)
Expand Down
33 changes: 33 additions & 0 deletions src/utils/authentication.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2025 Adobe. All rights reserved.
* This file is licensed to you 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 REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

const SERVICE_CODE = 'dx_aem_perf';

export const isAdmin = (context) => {
const { attributes: { authInfo: { scopes } } } = context;
return scopes.some((scope) => scope.name === 'admin');
};

export const userBelongsToOrg = (context) => {
const {
attributes: { authInfo: { profile } },
Comment thread
dzehnder marked this conversation as resolved.
Outdated
params: { organizationId },
} = context;
return profile.id === organizationId || isAdmin(context);
Comment thread
dzehnder marked this conversation as resolved.
Outdated
};

export const userHasSubService = (context, subservice) => {
const { attributes: { authInfo: { scopes } } } = context;
Comment thread
dzehnder marked this conversation as resolved.
Outdated
return scopes.some(
Comment thread
dzehnder marked this conversation as resolved.
Outdated
(scope) => scope.name === 'user' && scope.subScopes.includes(`${SERVICE_CODE}_${subservice}`),
);
};