Skip to content

Commit 6cdc316

Browse files
feat: ZO-191 - UUID and PIN should be different for each meeting
feat: ZO-191 - UUID and PIN should be different for each meeting
2 parents d720965 + 8e3240c commit 6cdc316

23 files changed

+174
-89
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
ovc-backend.iml
1111

1212
.env
13+
src/main/resources/application-dev.yaml

src/main/java/net/nordeck/ovc/backend/controller/MeetingController.java

+9-9
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public MeetingController(
124124
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
125125
schema = @Schema(implementation = ApiErrorDTO.class)))
126126
})
127-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
127+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
128128
public ResponseEntity<MeetingsPageDTO> findMeetings(
129129
@Parameter(description = "The type of meeting to be retrieved: 'normal', 'static', 'instant'")
130130
@RequestParam(defaultValue = "normal", required = false) String type,
@@ -193,7 +193,7 @@ public ResponseEntity<MeetingsPageDTO> findMeetings(
193193
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
194194
schema = @Schema(implementation = ApiErrorDTO.class)))
195195
})
196-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
196+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
197197
public ResponseEntity<MeetingDTO> findById(
198198
@Parameter(description = "Id of the meeting.", required = true)
199199
@PathVariable UUID mId)
@@ -346,7 +346,7 @@ public ResponseEntity<MeetingPermissionsDTO> getPermissions(
346346
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
347347
schema = @Schema(implementation = ApiErrorDTO.class)))
348348
})
349-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
349+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
350350
public ResponseEntity<MeetingDTO> createMeeting(
351351
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "The meeting to be created")
352352
@RequestBody MeetingCreateDTO meeting)
@@ -389,7 +389,7 @@ public ResponseEntity<MeetingDTO> createMeeting(
389389
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
390390
schema = @Schema(implementation = ApiErrorDTO.class)))
391391
})
392-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
392+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
393393
public ResponseEntity<MeetingDTO> updateMeeting(
394394
@Parameter(description = "Id of the meeting to be updated.", required = true)
395395
@PathVariable UUID mId,
@@ -550,7 +550,7 @@ public String generateLink(
550550
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
551551
schema = @Schema(implementation = ApiErrorDTO.class)))
552552
})
553-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
553+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
554554
public ResponseEntity<List<MeetingParticipantDTO>> listParticipants(
555555
@Parameter(description = "Id of the meeting to get the participants list.", required = true)
556556
@PathVariable UUID mId)
@@ -591,7 +591,7 @@ public ResponseEntity<List<MeetingParticipantDTO>> listParticipants(
591591
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
592592
schema = @Schema(implementation = ApiErrorDTO.class)))
593593
})
594-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
594+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
595595
public ResponseEntity<MeetingParticipantDTO> createParticipant(
596596
@Parameter(description = "Id of the meeting.", required = true)
597597
@PathVariable UUID mId,
@@ -634,7 +634,7 @@ public ResponseEntity<MeetingParticipantDTO> createParticipant(
634634
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
635635
schema = @Schema(implementation = ApiErrorDTO.class)))
636636
})
637-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
637+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
638638
public ResponseEntity<MeetingParticipantDTO> updateParticipant(
639639
@Parameter(description = "Id of the meeting.", required = true)
640640
@PathVariable UUID mId,
@@ -677,7 +677,7 @@ public ResponseEntity<MeetingParticipantDTO> updateParticipant(
677677
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
678678
schema = @Schema(implementation = ApiErrorDTO.class)))
679679
})
680-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
680+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
681681
public ResponseEntity<Void> deleteParticipant(
682682
@Parameter(description = "Id of the meeting.", required = true)
683683
@PathVariable UUID mId,
@@ -716,7 +716,7 @@ public ResponseEntity<Void> deleteParticipant(
716716
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
717717
schema = @Schema(implementation = ApiErrorDTO.class)))
718718
})
719-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
719+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
720720
public boolean isRegisteredUser(
721721
@Parameter(description = "Id (email) of the user to be checked.", required = true)
722722
@PathVariable String userId)

src/main/java/net/nordeck/ovc/backend/controller/NotificationController.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public class NotificationController
9393
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
9494
schema = @Schema(implementation = ApiErrorDTO.class)))
9595
})
96-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
96+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
9797
public ResponseEntity<NotificationsPageDTO> findForUser(
9898
@Parameter(description = "The amount of items to return. Default value is 20.")
9999
@RequestParam(required = false, defaultValue = "20") Integer pageSize,
@@ -138,7 +138,7 @@ public ResponseEntity<NotificationsPageDTO> findForUser(
138138
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
139139
schema = @Schema(implementation = ApiErrorDTO.class)))
140140
})
141-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
141+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
142142
public ResponseEntity<Void> delete(
143143
@Parameter(description = "Id of the to be deleted.", required = true)
144144
@PathVariable UUID id)
@@ -167,7 +167,7 @@ public ResponseEntity<Void> delete(
167167
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
168168
schema = @Schema(implementation = ApiErrorDTO.class)))
169169
})
170-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
170+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
171171
public ResponseEntity<Void> deleteAll()
172172
{
173173
Void delete = service.deleteAllForUser();
@@ -206,7 +206,7 @@ public ResponseEntity<Void> deleteAll()
206206
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
207207
schema = @Schema(implementation = ApiErrorDTO.class))),
208208
})
209-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
209+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
210210
public ResponseEntity<Void> updateView(
211211
@Parameter(description = "Id of the notification to be updated.", required = true)
212212
@PathVariable UUID id)
@@ -237,7 +237,7 @@ public ResponseEntity<Void> updateView(
237237
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
238238
schema = @Schema(implementation = ApiErrorDTO.class))),
239239
})
240-
@PreAuthorize("hasAuthority('default-roles-vk-bund')")
240+
@PreAuthorize("@rolesAuthorization.hasBasicAccessRole")
241241
public ResponseEntity<Void> updateViewAll()
242242
{
243243
logger.logRequest("Endpoint 'updateViewAll' called.");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package net.nordeck.ovc.backend.controller;
2+
3+
import lombok.Getter;
4+
import org.apache.commons.lang3.StringUtils;
5+
import org.springframework.beans.factory.annotation.Value;
6+
import org.springframework.security.core.GrantedAuthority;
7+
import org.springframework.security.core.context.SecurityContextHolder;
8+
import org.springframework.stereotype.Component;
9+
10+
import java.util.Collection;
11+
12+
13+
@Component("rolesAuthorization")
14+
public class RolesAuthorization
15+
{
16+
17+
@Value("${api.basic-access-role}")
18+
@Getter
19+
protected String basicAccessRole;
20+
21+
public boolean hasBasicAccessRole()
22+
{
23+
if (!SecurityContextHolder.getContext().getAuthentication().isAuthenticated())
24+
{
25+
return false;
26+
}
27+
Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
28+
if (StringUtils.isEmpty(basicAccessRole))
29+
{
30+
return true;
31+
}
32+
return authorities.stream().anyMatch(a -> a.getAuthority().equalsIgnoreCase(basicAccessRole));
33+
}
34+
35+
}
36+

src/main/java/net/nordeck/ovc/backend/dto/DTOUtils.java

+1
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ protected static void setBasicDataFromEntity(MeetingAbstractDTO dto, MeetingEnti
171171
dto.setLobbyEnabled(entity.isLobbyEnabled());
172172
dto.setPassword(entity.getPassword());
173173
dto.setType(getTypeFromEntity(entity));
174+
dto.setStartedAt(entity.getStartedAt());
174175
}
175176

176177
protected static RecurrenceDTO buildRecurrenceFromEntity(MeetingEntity entity)

src/main/java/net/nordeck/ovc/backend/dto/MeetingAbstractDTO.java

+8
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,12 @@ public class MeetingAbstractDTO
8080
@JsonProperty("lobby_enabled")
8181
private boolean lobbyEnabled;
8282

83+
@Schema(description = "The time UTC datetime in ISO-8601 format the meeting has been started. " +
84+
"Needs to be converted by the client with its own zone offset. " +
85+
"Relevant for INSTANT meeting.")
86+
@JsonProperty("started_at")
87+
@JsonSerialize(using = ZonedDateTimeSerializer.class)
88+
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = Constants.DATE_TIME_ISO_8601_FORMAT)
89+
private ZonedDateTime startedAt;
90+
8391
}

src/main/java/net/nordeck/ovc/backend/entity/MeetingEntity.java

+4
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ public class MeetingEntity {
147147
@Column(name = "excluded")
148148
private boolean excluded;
149149

150+
@Column(name = "started_at")
151+
private ZonedDateTime startedAt;
152+
150153
@OneToMany(mappedBy = "meetingId", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
151154
private List<MeetingParticipantEntity> participants;
152155

@@ -170,6 +173,7 @@ public static MeetingEntity buildFromMeetingAbstractDTO(MeetingAbstractDTO dto)
170173
.frequency(frequency)
171174
.password(dto.getPassword())
172175
.lobbyEnabled(dto.isLobbyEnabled())
176+
.startedAt(dto.getStartedAt())
173177
.build();
174178

175179
setRecurrence(dto, entity);

src/main/resources/liquibase/changelog-init.xml

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
2-
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
2+
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
35
<property name="NOW" value="now() " dbms="mysql,h2"/>
46
<property name="NOW" value="CURRENT_TIMESTAMP" dbms="postgresql"/>
57
<property name="NOW" value="sysdate" dbms="oracle"/>
@@ -48,6 +50,7 @@
4850
<column defaultValueBoolean="false" name="excluded" type="BOOLEAN"/>
4951
<column name="sip_jibri_link" type="VARCHAR(255)"/>
5052
<column name="series_end_time" type="TIMESTAMP WITH TIME ZONE"/>
53+
<column name="started_at" type="TIMESTAMP WITHOUT TIME ZONE"/>
5154
</createTable>
5255
</changeSet>
5356
<changeSet author="wagner.wutzke" id="1740266386086-2">
@@ -271,4 +274,4 @@
271274
<changeSet author="wagner.wutzke" id="1740266386086-27">
272275
<addForeignKeyConstraint baseColumnNames="step_execution_id" baseTableName="batch_step_execution_context" constraintName="step_exec_ctx_fk" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="step_execution_id" referencedTableName="batch_step_execution" validate="true"/>
273276
</changeSet>
274-
</databaseChangeLog>
277+
</databaseChangeLog>

src/test/java/net/nordeck/ovc/backend/TestUtils.java

+17-7
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,18 @@
55
import net.nordeck.ovc.backend.entity.MeetingParticipantEntity;
66
import net.nordeck.ovc.backend.entity.NotificationEntity;
77
import org.springframework.security.core.Authentication;
8+
import org.springframework.security.core.GrantedAuthority;
9+
import org.springframework.security.core.authority.SimpleGrantedAuthority;
810
import org.springframework.security.core.context.SecurityContextHolder;
911
import org.springframework.security.oauth2.jwt.Jwt;
12+
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
1013

1114
import java.time.Instant;
1215
import java.time.ZonedDateTime;
1316
import java.time.temporal.ChronoUnit;
14-
import java.util.HashMap;
15-
import java.util.List;
16-
import java.util.Map;
17-
import java.util.UUID;
17+
import java.util.*;
1818

1919
import static net.nordeck.ovc.backend.service.NotificationService.DELETE_CANDIDATE;
20-
import static org.mockito.Mockito.when;
2120

2221

2322
public class TestUtils
@@ -187,7 +186,7 @@ public static NotificationDTO getNotificationDTO()
187186
return NotificationDTO.buildFromEntity(getNotificationEntity());
188187
}
189188

190-
public static void initSecurityContext(Authentication auth, String email)
189+
public static Authentication initSecurityContext(String email, List<String> roles)
191190
{
192191
Map<String, Object> claims = new HashMap<>();
193192
if (email == null)
@@ -203,8 +202,19 @@ public static void initSecurityContext(Authentication auth, String email)
203202
HashMap<String, Object> headers = new HashMap<>();
204203
headers.put("auth", "Bearer");
205204
Jwt token = new Jwt("123456", Instant.now(), expiresAt, headers, claims);
206-
when(auth.getPrincipal()).thenReturn(token);
205+
206+
List<GrantedAuthority> authorities = new ArrayList<>();
207+
if (roles != null)
208+
{
209+
for(String role : roles)
210+
{
211+
authorities.add(new SimpleGrantedAuthority(role));
212+
}
213+
}
214+
JwtAuthenticationToken auth = new JwtAuthenticationToken(token, authorities, "auth-token");
207215
SecurityContextHolder.getContext().setAuthentication(auth);
216+
auth.setAuthenticated(true);
217+
return auth;
208218
}
209219

210220
}

src/test/java/net/nordeck/ovc/backend/controller/MeetingControllerTest.java

+1-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import org.junit.jupiter.api.AfterEach;
1111
import org.junit.jupiter.api.BeforeEach;
1212
import org.junit.jupiter.api.Test;
13-
import org.mockito.Mock;
1413
import org.springframework.beans.factory.annotation.Autowired;
1514
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
1615
import org.springframework.boot.test.context.SpringBootTest;
@@ -59,9 +58,7 @@ public class MeetingControllerTest
5958
private MeetingParticipantRequestDTO participantRequestDTO;
6059
private String json, jsonResponse;
6160

62-
63-
@Mock
64-
private Authentication auth;
61+
private Authentication auth = TestUtils.initSecurityContext(null, null);;
6562

6663
@BeforeEach
6764
void initData() throws IOException
@@ -72,8 +69,6 @@ void initData() throws IOException
7269

7370
json = objectMapper.writeValueAsString(participantRequestDTO);
7471
jsonResponse = objectMapper.writeValueAsString(participantDTO);
75-
76-
TestUtils.initSecurityContext(auth, null);
7772
}
7873

7974
@AfterEach

src/test/java/net/nordeck/ovc/backend/controller/NotificationControllerTest.java

+2-11
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package net.nordeck.ovc.backend.controller;
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import net.nordeck.ovc.backend.TestUtils;
45
import net.nordeck.ovc.backend.dto.NotificationDTO;
56
import net.nordeck.ovc.backend.dto.NotificationsPageDTO;
6-
import net.nordeck.ovc.backend.TestUtils;
77
import net.nordeck.ovc.backend.service.NotificationService;
88
import org.junit.jupiter.api.AfterEach;
9-
import org.junit.jupiter.api.BeforeEach;
109
import org.junit.jupiter.api.Test;
11-
import org.mockito.Mock;
1210
import org.springframework.beans.factory.annotation.Autowired;
1311
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
1412
import org.springframework.boot.test.context.SpringBootTest;
@@ -42,14 +40,7 @@ public class NotificationControllerTest
4240
@MockBean
4341
NotificationService service;
4442

45-
@Mock
46-
private Authentication auth;
47-
48-
@BeforeEach
49-
void initBeforeEach()
50-
{
51-
TestUtils.initSecurityContext(auth, null);
52-
}
43+
Authentication auth = TestUtils.initSecurityContext(null, null);
5344

5445
@AfterEach
5546
void finishAfterEach()

src/test/java/net/nordeck/ovc/backend/controller/RestExceptionHandlerTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import io.jsonwebtoken.security.InvalidKeyException;
44
import jakarta.persistence.EntityNotFoundException;
55
import jakarta.validation.ConstraintViolationException;
6-
import net.nordeck.ovc.backend.dto.ApiErrorDTO;
76
import net.nordeck.ovc.backend.Constants;
7+
import net.nordeck.ovc.backend.dto.ApiErrorDTO;
88
import org.junit.jupiter.api.AfterAll;
99
import org.junit.jupiter.api.BeforeAll;
1010
import org.junit.jupiter.api.Test;

0 commit comments

Comments
 (0)