chore: Add actor type check + more tests (#10005)
This commit is contained in:
1 parent
c7b24eb3ec
commit
094971775b
5 files changed
+140
-10
No files matched your search
@@ -230,6 +230,57 @@ medusaIntegrationTestRunner({
|
|||||||
expect(login.data).toEqual({ token: expect.any(String) })
|
expect(login.data).toEqual({ token: expect.any(String) })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should ensure you can only update password", async () => {
|
||||||
|
// Register user
|
||||||
|
await api.post("/auth/user/emailpass/register", {
|
||||||
|
email: "test@medusa-commerce.com",
|
||||||
|
password: "secret_password",
|
||||||
|
})
|
||||||
|
|
||||||
|
// The token won't be part of the Rest API response, so we need to generate it manually
|
||||||
|
const { result } = await generateResetPasswordTokenWorkflow(
|
||||||
|
container
|
||||||
|
).run({
|
||||||
|
input: {
|
||||||
|
entityId: "test@medusa-commerce.com",
|
||||||
|
actorType: "user",
|
||||||
|
provider: "emailpass",
|
||||||
|
secret: "test",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/auth/user/emailpass/update?token=${result}`,
|
||||||
|
{
|
||||||
|
email: "test+new@medusa-commerce.com",
|
||||||
|
password: "new_password",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data).toEqual({ success: true })
|
||||||
|
|
||||||
|
const failedLogin = await api
|
||||||
|
.post("/auth/user/emailpass", {
|
||||||
|
email: "test+new@medusa-commerce.com",
|
||||||
|
password: "new_password",
|
||||||
|
})
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(failedLogin.response.status).toEqual(401)
|
||||||
|
expect(failedLogin.response.data.message).toEqual(
|
||||||
|
"Invalid email or password"
|
||||||
|
)
|
||||||
|
|
||||||
|
const login = await api.post("/auth/user/emailpass", {
|
||||||
|
email: "test@medusa-commerce.com",
|
||||||
|
password: "new_password",
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(login.status).toEqual(200)
|
||||||
|
expect(login.data).toEqual({ token: expect.any(String) })
|
||||||
|
})
|
||||||
|
|
||||||
it("should fail if token has expired", async () => {
|
it("should fail if token has expired", async () => {
|
||||||
jest.useFakeTimers()
|
jest.useFakeTimers()
|
||||||
|
|
||||||
@@ -286,6 +337,76 @@ medusaIntegrationTestRunner({
|
|||||||
expect(response.response.status).toEqual(401)
|
expect(response.response.status).toEqual(401)
|
||||||
expect(response.response.data.message).toEqual("Invalid token")
|
expect(response.response.data.message).toEqual("Invalid token")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should fail if update is attempted on different actor type", async () => {
|
||||||
|
jest.useFakeTimers()
|
||||||
|
|
||||||
|
// Register user
|
||||||
|
await api.post("/auth/user/emailpass/register", {
|
||||||
|
email: "test@medusa-commerce.com",
|
||||||
|
password: "secret_password",
|
||||||
|
})
|
||||||
|
|
||||||
|
// The token won't be part of the Rest API response, so we need to generate it manually
|
||||||
|
const { result } = await generateResetPasswordTokenWorkflow(
|
||||||
|
container
|
||||||
|
).run({
|
||||||
|
input: {
|
||||||
|
entityId: "test@medusa-commerce.com",
|
||||||
|
actorType: "user",
|
||||||
|
provider: "emailpass",
|
||||||
|
secret: "test",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Advance time by 15 minutes
|
||||||
|
jest.advanceTimersByTime(15 * 60 * 1000)
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post(`/auth/customer/emailpass/update?token=${result}`, {
|
||||||
|
email: "test@medusa-commerce.com",
|
||||||
|
password: "new_password",
|
||||||
|
})
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(response.response.status).toEqual(401)
|
||||||
|
expect(response.response.data.message).toEqual("Invalid token")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should fail if token secret is incorrect", async () => {
|
||||||
|
jest.useFakeTimers()
|
||||||
|
|
||||||
|
// Register user
|
||||||
|
await api.post("/auth/user/emailpass/register", {
|
||||||
|
email: "test@medusa-commerce.com",
|
||||||
|
password: "secret_password",
|
||||||
|
})
|
||||||
|
|
||||||
|
// The token won't be part of the Rest API response, so we need to generate it manually
|
||||||
|
const { result } = await generateResetPasswordTokenWorkflow(
|
||||||
|
container
|
||||||
|
).run({
|
||||||
|
input: {
|
||||||
|
entityId: "test@medusa-commerce.com",
|
||||||
|
actorType: "user",
|
||||||
|
provider: "emailpass",
|
||||||
|
secret: "incorrect_secret",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Advance time by 15 minutes
|
||||||
|
jest.advanceTimersByTime(15 * 60 * 1000)
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post(`/auth/user/emailpass/update?token=${result}`, {
|
||||||
|
email: "test@medusa-commerce.com",
|
||||||
|
password: "new_password",
|
||||||
|
})
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(response.response.status).toEqual(401)
|
||||||
|
expect(response.response.data.message).toEqual("Invalid token")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should refresh the token successfully", async () => {
|
it("should refresh the token successfully", async () => {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export const generateResetPasswordTokenWorkflow = createWorkflow(
|
|||||||
{
|
{
|
||||||
entity_id: input.entityId,
|
entity_id: input.entityId,
|
||||||
provider: input.provider,
|
provider: input.provider,
|
||||||
|
actor_type: input.actorType,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
secret: input.secret,
|
secret: input.secret,
|
||||||
|
|||||||
@@ -13,9 +13,14 @@ export const POST = async (
|
|||||||
|
|
||||||
const authService = req.scope.resolve<IAuthModuleService>(Modules.AUTH)
|
const authService = req.scope.resolve<IAuthModuleService>(Modules.AUTH)
|
||||||
|
|
||||||
|
const updateData = {
|
||||||
|
...(req.body as Record<string, unknown>),
|
||||||
|
entity_id: req.auth_context.actor_id, // comes from the validated token
|
||||||
|
}
|
||||||
|
|
||||||
const { authIdentity, success, error } = await authService.updateProvider(
|
const { authIdentity, success, error } = await authService.updateProvider(
|
||||||
auth_provider,
|
auth_provider,
|
||||||
req.body as Record<string, unknown>
|
updateData
|
||||||
)
|
)
|
||||||
|
|
||||||
if (success && authIdentity) {
|
if (success && authIdentity) {
|
||||||
|
|||||||
@@ -46,6 +46,11 @@ export const validateToken = () => {
|
|||||||
return next(errorObject)
|
return next(errorObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// E.g. token was requested for a customer, but attempted used for a user
|
||||||
|
if (decoded?.actor_type !== actor_type) {
|
||||||
|
return next(errorObject)
|
||||||
|
}
|
||||||
|
|
||||||
const [providerIdentity] = await authModule.listProviderIdentities(
|
const [providerIdentity] = await authModule.listProviderIdentities(
|
||||||
{
|
{
|
||||||
entity_id: decoded.entity_id,
|
entity_id: decoded.entity_id,
|
||||||
@@ -60,17 +65,15 @@ export const validateToken = () => {
|
|||||||
return next(errorObject)
|
return next(errorObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
let verified: JwtPayload | null = null
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
verified = verify(token as string, http.jwtSecret as string) as JwtPayload
|
verify(token as string, http.jwtSecret as string) as JwtPayload
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return next(errorObject)
|
return next(errorObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
req_.auth_context = {
|
req_.auth_context = {
|
||||||
actor_type,
|
actor_type,
|
||||||
auth_identity_id: verified.auth_identity_id!,
|
auth_identity_id: providerIdentity.auth_identity_id!,
|
||||||
actor_id: providerIdentity.entity_id,
|
actor_id: providerIdentity.entity_id,
|
||||||
app_metadata: {},
|
app_metadata: {},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,15 +43,15 @@ export class EmailPassAuthService extends AbstractAuthModuleProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update(
|
async update(
|
||||||
data: { email: string; password: string },
|
data: { password: string; entity_id: string },
|
||||||
authIdentityService: AuthIdentityProviderService
|
authIdentityService: AuthIdentityProviderService
|
||||||
) {
|
) {
|
||||||
const { email, password } = data ?? {}
|
const { password, entity_id } = data ?? {}
|
||||||
|
|
||||||
if (!email || !isString(email)) {
|
if (!entity_id) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `Cannot update ${this.provider} provider identity without email`,
|
error: `Cannot update ${this.provider} provider identity without entity_id`,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ export class EmailPassAuthService extends AbstractAuthModuleProvider {
|
|||||||
try {
|
try {
|
||||||
const passwordHash = await this.hashPassword(password)
|
const passwordHash = await this.hashPassword(password)
|
||||||
|
|
||||||
authIdentity = await authIdentityService.update(email, {
|
authIdentity = await authIdentityService.update(entity_id, {
|
||||||
provider_metadata: {
|
provider_metadata: {
|
||||||
password: passwordHash,
|
password: passwordHash,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in new issue
Block a user