Skip to content

Commit 3dc7dfc

Browse files
committed
fix(backoffice): only allow admin users.
1 parent 7b58ae5 commit 3dc7dfc

4 files changed

Lines changed: 38 additions & 2 deletions

File tree

services/backend/src/main/java/com/survey/backend/service/LoginService.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ public LoginResponseDTO login(LoginRequestDTO request) {
7878
User user = userService.saveUser(email);
7979
List<String> roles = keycloakAdminService.getUserRoles(email);
8080

81+
if ("backoffice".equalsIgnoreCase(keycloakClientId)) {
82+
boolean hasAccess =
83+
roles.stream()
84+
.anyMatch(
85+
r ->
86+
r.equalsIgnoreCase(KeycloakRole.ADMIN.name())
87+
|| r.equalsIgnoreCase(KeycloakRole.MANAGER.name()));
88+
if (!hasAccess) {
89+
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Unauthorized");
90+
}
91+
}
92+
8193
return new LoginResponseDTO(accessToken, roles, user.isPremium());
8294
}
8395

services/backend/src/test/java/com/survey/backend/controller/AuthControllerTest.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public void testLoginSuccess() throws Exception {
6969
User mockUser = User.builder().email("x@test.com").isPremium(true).build();
7070

7171
Mockito.when(userService.saveUser(email)).thenReturn(mockUser);
72-
Mockito.when(keycloakAdminService.getUserRoles(email)).thenReturn(List.of("CUSTOMER"));
72+
Mockito.when(keycloakAdminService.getUserRoles(email)).thenReturn(List.of("Admin"));
7373

7474
mockMvc
7575
.perform(
@@ -120,4 +120,24 @@ public void testSignupSuccess() throws Exception {
120120
.createUser("new@example.com", "pw", List.of(KeycloakRole.CUSTOMER.name()));
121121
Mockito.verify(userService).saveUser("new@example.com");
122122
}
123+
124+
@Test
125+
public void testLoginFailsWhenUserNotAdminOrManager() throws Exception {
126+
LoginRequestDTO loginRequest = new LoginRequestDTO();
127+
loginRequest.setEmail("test@example.com");
128+
loginRequest.setPassword("password");
129+
130+
String email = "test@example.com";
131+
132+
User mockUser = User.builder().email("x@test.com").isPremium(false).build();
133+
Mockito.when(userService.saveUser(email)).thenReturn(mockUser);
134+
Mockito.when(keycloakAdminService.getUserRoles(email)).thenReturn(List.of("CUSTOMER"));
135+
136+
mockMvc
137+
.perform(
138+
post("/auth/login")
139+
.contentType(MediaType.APPLICATION_JSON)
140+
.content(objectMapper.writeValueAsString(loginRequest)))
141+
.andExpect(status().isUnauthorized());
142+
}
123143
}

services/backoffice/src/app/user-management/containers/payments/payments.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Component, OnInit } from '@angular/core'
2-
import {DatePipe, NgFor} from '@angular/common'
2+
import { DatePipe, NgFor } from '@angular/common'
33
import { MatTableModule, MatTableDataSource } from '@angular/material/table'
44
import { Payment } from '../../models/payment'
55
import { PaymentsService } from '../../services/payment.service'

services/backoffice/src/app/user-management/services/keycloak.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ export class KeycloakService {
2222
return this.keycloak.init({ onLoad: 'login-required' }).then(() => {
2323
const token = this.keycloak?.token
2424
if (token) {
25+
const roles = (this.keycloak.tokenParsed?.['realm_access']?.['roles'] as string[]) || []
26+
if (!roles.map((r) => r.toLowerCase()).includes('admin')) {
27+
throw new Error('Unauthorized')
28+
}
2529
Cookies.set('token', token, {
2630
secure: true,
2731
sameSite: 'strict',

0 commit comments

Comments
 (0)