Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix: Broken re-login after logout fails #8694

Merged
merged 1 commit into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Bugfix: Broken re-login after logout

After a user logged out, it was no longer possible to login without reloading the ocis root domain,
this has now been fixed and only allowed query-params are taken into account.

https://github.com/owncloud/web/pull/8694
14 changes: 13 additions & 1 deletion packages/web-runtime/src/router/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { base, router } from './index'
import { RouteLocation, RouteParams, Router, RouteRecordNormalized } from 'vue-router'
import pick from 'lodash-es/pick'
import {
AuthContext,
authContextValues,
Expand All @@ -10,7 +11,18 @@ import {
export const buildUrl = (pathname) => {
const isHistoryMode = !!base
const baseUrl = new URL(window.location.href.split('#')[0])
baseUrl.search = window.location.search

// searchParams defines a set of search parameters which should be part of new url.
// The resulting querystring only contains the properties listed here.
const searchParams = new URLSearchParams(
pick(Object.fromEntries(new URLSearchParams(window.location.search).entries()), [
// needed for private links
'details'
])
).toString()

baseUrl.search = searchParams

if (isHistoryMode) {
// in history mode we can't determine the base path, it must be provided by the document
baseUrl.pathname = new URL(base.href).pathname
Expand Down
20 changes: 13 additions & 7 deletions packages/web-runtime/src/services/auth/authService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { extractPublicLinkToken, isPublicLinkContext, isUserContext } from '../.
import { unref } from 'vue'
import { Ability } from 'web-pkg/src/utils'
import { Language } from 'vue3-gettext'
import pick from 'lodash-es/pick'

export class AuthService {
private clientService: ClientService
Expand Down Expand Up @@ -164,20 +165,25 @@ export class AuthService {
* Sign in callback gets called from the IDP after initial login.
*/
public async signInCallback() {
// craft a url that the parser in oidc-client-ts can handle… this is required for oauth2 logins
const url =
'/?' +
new URLSearchParams(
unref(this.router.currentRoute).query as Record<string, string>
).toString()
const currentQuery = unref(this.router.currentRoute).query
// craft an url that the parser in oidc-client-ts can handle… this is required for oauth2 logins
const url = '/?' + new URLSearchParams(currentQuery as Record<string, string>).toString()

try {
await this.userManager.signinRedirectCallback(url)

const redirectUrl = this.userManager.getAndClearPostLoginRedirectUrl()

// transportQuery defines a set of query parameters which should be part of router route replace.
// The resulting object only contains the properties listed here.
const transportQuery = pick(currentQuery, [
// needed for private links
'details'
])

return this.router.replace({
path: redirectUrl,
query: unref(this.router.currentRoute).query
query: transportQuery
})
} catch (e) {
console.warn('error during authentication:', e)
Expand Down
3 changes: 3 additions & 0 deletions packages/web-runtime/tests/unit/router/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ describe('buildUrl', () => {
${'https://localhost:9200/files/list/all'} | ${'/foo'} | ${'/login/foo'} | ${'https://localhost:9200/foo/login/foo'}
${'https://localhost:9200/files/list/all'} | ${'/'} | ${'/bar.html'} | ${'https://localhost:9200/bar.html'}
${'https://localhost:9200/files/list/all'} | ${'/foo'} | ${'/bar.html'} | ${'https://localhost:9200/foo/bar.html'}
${'https://localhost:9200/files/list/all?details=91953740'} | ${'/foo'} | ${'/bar.html'} | ${'https://localhost:9200/foo/bar.html?details=91953740'}
${'https://localhost:9200/files/list/all?details=91953740&unknown=87987987'} | ${'/foo'} | ${'/bar.html'} | ${'https://localhost:9200/foo/bar.html?details=91953740'}
${'https://localhost:9200/files/list/all?unknown=87987987'} | ${'/foo'} | ${'/bar.html'} | ${'https://localhost:9200/foo/bar.html'}
`('$path -> $expected', async ({ location, base, path, expected }) => {
delete window.location
window.location = new URL(location) as any
Expand Down
27 changes: 27 additions & 0 deletions packages/web-runtime/tests/unit/services/auth/authService.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { AuthService } from 'web-runtime/src/services/auth/authService'

describe('AuthService', () => {
describe('signInCallback', () => {
it.each([
[{ details: 'details' }, { details: 'details' }],
[{ details: 'details', unknown: 'unknown' }, { details: 'details' }],
[{ unknown: 'unknown' }, {}]
])('forwards only whitelisted query parameters: %s = %s', async (query, expected: any) => {
const authService = new AuthService()
const replace = jest.fn()

jest.replaceProperty(authService as any, 'userManager', {
signinRedirectCallback: jest.fn(),
getAndClearPostLoginRedirectUrl: jest.fn()
})

jest.replaceProperty(authService as any, 'router', {
currentRoute: { query },
replace
})
await authService.signInCallback()

expect(replace.mock.calls[0][0].query).toEqual(expected)
})
})
})