Skip to content

Commit ec55180

Browse files
committed
Allow admin console to connect to keycloak
1 parent 29a89ed commit ec55180

File tree

7 files changed

+134
-21
lines changed

7 files changed

+134
-21
lines changed

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ RUN npm run build
1010
# Server step
1111
FROM nginx:1.27 AS production-stage
1212
COPY --from=builder /app/dist /usr/share/nginx/html
13+
14+
EXPOSE 80

docker-compose.yml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
services:
2+
web:
3+
image: kuzzleio/kuzzle-runner:22
4+
command: npm run dev --prefix /var/app/ -- --host
5+
ports:
6+
- 8080:8080
7+
volumes:
8+
- .:/var/app
9+
210
kuzzle:
311
image: kuzzleio/kuzzle:2
412
ports:
@@ -20,17 +28,6 @@ services:
2028
interval: 5s
2129
retries: 30
2230

23-
web:
24-
image: kuzzleio/kuzzle-runner:22
25-
command: npm run dev --prefix /var/app/ -- --host
26-
ports:
27-
- 8080:8080
28-
depends_on:
29-
kuzzle:
30-
condition: service_healthy
31-
volumes:
32-
- .:/var/app
33-
3431
redis:
3532
image: redis:5
3633
ports:

src/components/Common/Login/Form.vue

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,42 @@
3232
<b-alert variant="danger" show dismissible> Login failed: {{ error }} </b-alert>
3333
</div>
3434

35-
<div class="LoginForm-buttons float-right mt-3">
36-
<b-button class="mr-3" data-cy="LoginAsAnonymous-Btn" variant="link" @click="loginAsAnonymous"
37-
>Login as Anonymous</b-button
38-
>
39-
<b-button variant="primary" data-cy="Login-submitBtn" type="submit" name="action" tabindex="3"
40-
>Login</b-button
41-
>
35+
<div class="LoginForm-buttons">
36+
<div class="d-flex flex-column align-items-center w-100 gap-3">
37+
<div class="w-100 d-flex justify-content-center mt-2">
38+
<b-button
39+
class="w-100"
40+
variant="primary"
41+
data-cy="Login-submitBtn"
42+
type="submit"
43+
name="action"
44+
tabindex="3"
45+
>Login</b-button
46+
>
47+
</div>
48+
49+
<div v-for="strategy in strategies" class="w-100 d-flex justify-content-center mt-2">
50+
<b-button
51+
class="w-100"
52+
variant="primary"
53+
data-cy="Login-submitBtn"
54+
name="action"
55+
@click="loginWithStrategy(strategy)"
56+
tabindex="4"
57+
>Login with {{ strategy }}</b-button
58+
>
59+
</div>
60+
61+
<div class="w-100 d-flex justify-content-center mt-2">
62+
<b-button
63+
class="w-100"
64+
data-cy="LoginAsAnonymous-Btn"
65+
variant="primary"
66+
@click="loginAsAnonymous"
67+
>Login as Anonymous</b-button
68+
>
69+
</div>
70+
</div>
4271
</div>
4372
</form>
4473
</template>
@@ -67,6 +96,7 @@ export default {
6796
username: null,
6897
password: null,
6998
error: '',
99+
strategies: ['keycloak'],
70100
};
71101
},
72102
computed: {
@@ -114,6 +144,34 @@ export default {
114144
this.error = error.message;
115145
}
116146
},
147+
148+
async loginWithStrategy(strategy) {
149+
if (!strategy) {
150+
return;
151+
}
152+
153+
if (strategy !== 'keycloak') {
154+
this.error = 'Strategy not supported yet.';
155+
return;
156+
}
157+
158+
this.error = '';
159+
this.$kuzzle.jwt = null;
160+
161+
try {
162+
const response = await this.$kuzzle.query({
163+
controller: 'auth',
164+
action: 'login',
165+
strategy: 'keycloak',
166+
});
167+
168+
localStorage.setItem('openid-sessionId', response.headers.keycloak);
169+
window.location.href = response.headers.location;
170+
} catch (error) {
171+
this.error = error.message;
172+
localStorage.removeItem('openid-sessionId');
173+
}
174+
},
117175
},
118176
};
119177
</script>

src/stores/auth.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,22 @@ export const useAuthStore = defineStore('auth', {
243243
async init() {
244244
this.reset();
245245
this.initializing = true;
246+
const kuzzleStore = useKuzzleStore();
247+
const kuzzle = kuzzleStore.$kuzzle;
248+
249+
if (kuzzle === null) {
250+
throw new Error('Kuzzle is not initialized');
251+
}
252+
246253
await this.checkFirstAdmin();
247-
await this.loginByToken();
254+
255+
const sessionId = localStorage.getItem('openid-sessionId');
256+
257+
if (sessionId) {
258+
await this.loginByOpenId(sessionId);
259+
} else {
260+
await this.loginByToken();
261+
}
248262
},
249263
async createSingleUseToken(): Promise<string> {
250264
const kuzzleStore = useKuzzleStore();
@@ -318,6 +332,45 @@ export const useAuthStore = defineStore('auth', {
318332
const jwt = await kuzzle.auth.login('local', credentials, '2h');
319333
return await this.setSession(jwt);
320334
},
335+
336+
async loginByOpenId(sessionId: string) {
337+
const kuzzleStore = useKuzzleStore();
338+
const kuzzle = kuzzleStore.$kuzzle;
339+
340+
if (kuzzle === null) {
341+
throw new Error('Kuzzle is not initialized');
342+
}
343+
344+
if (kuzzleStore.currentEnvironment === null) {
345+
throw new Error('No current environment selected');
346+
}
347+
348+
const response = await kuzzle.query({
349+
controller: 'auth',
350+
action: 'login',
351+
strategy: 'keycloak',
352+
body: {
353+
sessionId: sessionId,
354+
callbackUrl: window.location.href,
355+
},
356+
});
357+
358+
kuzzle.jwt = null;
359+
360+
if (response.status === 200) {
361+
localStorage.removeItem('openid-sessionId');
362+
const res = await kuzzle.auth.checkToken(response.result.jwt);
363+
364+
if (!res.valid) {
365+
kuzzle.jwt = null;
366+
return await this.setSession(null);
367+
} else {
368+
kuzzle.jwt = response.result.jwt;
369+
return await this.setSession(response.result.jwt);
370+
}
371+
}
372+
},
373+
321374
async loginByToken() {
322375
const kuzzleStore = useKuzzleStore();
323376
const kuzzle = kuzzleStore.$kuzzle;

src/stores/kuzzle.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ export const useKuzzleStore = defineStore('kuzzle', {
9595

9696
localStorage.setItem(LS_ENVIRONMENTS, JSON.stringify(this.environments));
9797

98+
this.setCurrentEnvironment(payload.id);
99+
98100
return payload.id;
99101
},
100102
deleteEnvironment(id: string) {

src/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@ export const formatForDom = (word: string): string => {
2424

2525
export const sortObject = (object: object): object => {
2626
return Object.keys(object)
27-
.sort()
27+
.sort((a, b) => a.localeCompare(b))
2828
.reduce((result, key) => {
2929
result[key] = object[key];
3030
return result;
3131
}, {});
3232
};
3333

34+
3435
export const truncateName = (name: string, maxLength = 50): string => {
3536
if (name.length === 0) {
3637
return '';

vite.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export default defineConfig({
6060
},
6161
plugins: [vue(), visualizer()],
6262
preview: {
63-
port: 8080,
63+
port: 8082,
6464
},
6565
resolve: {
6666
alias: {

0 commit comments

Comments
 (0)