mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-30 17:53:31 -04:00 
			
		
		
		
	Fix OIDC infinite loop if user is not in OIDC_USER_GROUP (#3487)
This commit is contained in:
		| @@ -201,7 +201,7 @@ export default defineComponent({ | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     function isDirectLogin() { |     function isDirectLogin() { | ||||||
|         return router.currentRoute.query.direct |         return Object.keys(router.currentRoute.query).includes("direct") | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async function oidcAuthenticate() { |     async function oidcAuthenticate() { | ||||||
|   | |||||||
| @@ -16,7 +16,6 @@ export default class DynamicOpenIDConnectScheme extends OpenIDConnectScheme { | |||||||
|             this.$auth.$storage |             this.$auth.$storage | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
|         // eslint-disable-next-line @typescript-eslint/no-unsafe-return |         // eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||||||
|         return await super.mounted() |         return await super.mounted() | ||||||
|     } |     } | ||||||
| @@ -79,6 +78,7 @@ export default class DynamicOpenIDConnectScheme extends OpenIDConnectScheme { | |||||||
|         // Update tokens with mealie token |         // Update tokens with mealie token | ||||||
|         this.updateTokens(response) |         this.updateTokens(response) | ||||||
|       } catch { |       } catch { | ||||||
|  |         this.$auth.reset() | ||||||
|         const currentUrl = new URL(window.location.href) |         const currentUrl = new URL(window.location.href) | ||||||
|         if (currentUrl.pathname === "/login" && currentUrl.searchParams.has("direct")) { |         if (currentUrl.pathname === "/login" && currentUrl.searchParams.has("direct")) { | ||||||
|           return |           return | ||||||
|   | |||||||
| @@ -35,6 +35,8 @@ class OpenIDProvider(AuthProvider[OIDCRequest]): | |||||||
|         repos = get_repositories(self.session) |         repos = get_repositories(self.session) | ||||||
|  |  | ||||||
|         user = self.try_get_user(claims.get(settings.OIDC_USER_CLAIM)) |         user = self.try_get_user(claims.get(settings.OIDC_USER_CLAIM)) | ||||||
|  |         is_admin = False | ||||||
|  |         if settings.OIDC_USER_GROUP or settings.OIDC_ADMIN_GROUP: | ||||||
|             group_claim = claims.get("groups", []) |             group_claim = claims.get("groups", []) | ||||||
|             is_admin = settings.OIDC_ADMIN_GROUP in group_claim if settings.OIDC_ADMIN_GROUP else False |             is_admin = settings.OIDC_ADMIN_GROUP in group_claim if settings.OIDC_ADMIN_GROUP else False | ||||||
|             is_valid_user = settings.OIDC_USER_GROUP in group_claim if settings.OIDC_USER_GROUP else True |             is_valid_user = settings.OIDC_USER_GROUP in group_claim if settings.OIDC_USER_GROUP else True | ||||||
| @@ -68,7 +70,7 @@ class OpenIDProvider(AuthProvider[OIDCRequest]): | |||||||
|             return self.get_access_token(user, settings.OIDC_REMEMBER_ME)  # type: ignore |             return self.get_access_token(user, settings.OIDC_REMEMBER_ME)  # type: ignore | ||||||
|  |  | ||||||
|         if user: |         if user: | ||||||
|             if user.admin != is_admin: |             if settings.OIDC_ADMIN_GROUP and user.admin != is_admin: | ||||||
|                 self._logger.debug(f"[OIDC] {'Setting' if is_admin else 'Removing'} user as admin") |                 self._logger.debug(f"[OIDC] {'Setting' if is_admin else 'Removing'} user as admin") | ||||||
|                 user.admin = is_admin |                 user.admin = is_admin | ||||||
|                 repos.users.update(user.id, user) |                 repos.users.update(user.id, user) | ||||||
| @@ -91,6 +93,7 @@ class OpenIDProvider(AuthProvider[OIDCRequest]): | |||||||
|             self._logger.error( |             self._logger.error( | ||||||
|                 f"[OIDC] Unsupported algorithm '{algorithm}'. Unable to decode id token due to mismatched algorithm." |                 f"[OIDC] Unsupported algorithm '{algorithm}'. Unable to decode id token due to mismatched algorithm." | ||||||
|             ) |             ) | ||||||
|  |             return None | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             claims.validate() |             claims.validate() | ||||||
|   | |||||||
| @@ -30,6 +30,7 @@ services: | |||||||
|  |  | ||||||
|       OIDC_AUTH_ENABLED: True |       OIDC_AUTH_ENABLED: True | ||||||
|       OIDC_SIGNUP_ENABLED: True |       OIDC_SIGNUP_ENABLED: True | ||||||
|  |       OIDC_USER_GROUP: user | ||||||
|       OIDC_ADMIN_GROUP: admin |       OIDC_ADMIN_GROUP: admin | ||||||
|       OIDC_CONFIGURATION_URL: http://localhost:8080/default/.well-known/openid-configuration |       OIDC_CONFIGURATION_URL: http://localhost:8080/default/.well-known/openid-configuration | ||||||
|       OIDC_CLIENT_ID: default |       OIDC_CLIENT_ID: default | ||||||
|   | |||||||
| @@ -55,7 +55,8 @@ test('oidc initial login', async ({ page }) => { | |||||||
|         "sub": username, |         "sub": username, | ||||||
|         "email": `${username}@example.com`, |         "email": `${username}@example.com`, | ||||||
|         "preferred_username": username, |         "preferred_username": username, | ||||||
|         "name": name |         "name": name, | ||||||
|  |         "groups": ["user"] | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     await page.goto('http://localhost:9000/login'); |     await page.goto('http://localhost:9000/login'); | ||||||
| @@ -67,6 +68,26 @@ test('oidc initial login', async ({ page }) => { | |||||||
|     await expect(page.getByRole('link', { name: 'Settings' })).not.toBeVisible(); |     await expect(page.getByRole('link', { name: 'Settings' })).not.toBeVisible(); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | test('oidc login with user not in propery group', async ({ page }) => { | ||||||
|  |     const username = "testUserNoGroup" | ||||||
|  |     const name = "Test User No Group" | ||||||
|  |     const claims = { | ||||||
|  |         "sub": username, | ||||||
|  |         "email": `${username}@example.com`, | ||||||
|  |         "preferred_username": username, | ||||||
|  |         "name": name, | ||||||
|  |         "groups": [] | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     await page.goto('http://localhost:9000/login'); | ||||||
|  |     await page.getByRole('button', { name: 'Login with OAuth' }).click(); | ||||||
|  |     await page.getByPlaceholder('Enter any user/subject').fill(username); | ||||||
|  |     await page.getByPlaceholder('Optional claims JSON value,').fill(JSON.stringify(claims)); | ||||||
|  |     await page.getByRole('button', { name: 'Sign-in' }).click(); | ||||||
|  |     await expect(page).toHaveURL(/.*\/login\/?\?direct=1/) | ||||||
|  |     await expect(page.getByRole('button', { name: 'Login with OAuth' })).toBeVisible() | ||||||
|  | }); | ||||||
|  |  | ||||||
| test('oidc sequential login', async ({ page }) => { | test('oidc sequential login', async ({ page }) => { | ||||||
|     const username = "testUser2" |     const username = "testUser2" | ||||||
|     const name = "Test User 2" |     const name = "Test User 2" | ||||||
| @@ -74,7 +95,8 @@ test('oidc sequential login', async ({ page }) => { | |||||||
|         "sub": username, |         "sub": username, | ||||||
|         "email": `${username}@example.com`, |         "email": `${username}@example.com`, | ||||||
|         "preferred_username": username, |         "preferred_username": username, | ||||||
|         "name": name |         "name": name, | ||||||
|  |         "groups": ["user"] | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     await page.goto('http://localhost:9000/login'); |     await page.goto('http://localhost:9000/login'); | ||||||
| @@ -100,7 +122,8 @@ test('settings page verify oidc', async ({ page }) => { | |||||||
|         "sub": username, |         "sub": username, | ||||||
|         "email": `${username}@example.com`, |         "email": `${username}@example.com`, | ||||||
|         "preferred_username": username, |         "preferred_username": username, | ||||||
|         "name": name |         "name": name, | ||||||
|  |         "groups": ["user"] | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     await page.goto('http://localhost:9000/login'); |     await page.goto('http://localhost:9000/login'); | ||||||
| @@ -133,7 +156,7 @@ test('oidc admin user', async ({ page }) => { | |||||||
|         "email": `${username}@example.com`, |         "email": `${username}@example.com`, | ||||||
|         "preferred_username": username, |         "preferred_username": username, | ||||||
|         "name": name, |         "name": name, | ||||||
|         "groups": ["admin"] |         "groups": ["user", "admin"] | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     await page.goto('http://localhost:9000/login'); |     await page.goto('http://localhost:9000/login'); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user