Skip to content

Commit

Permalink
Per guild api authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
Alf-Melmac committed Oct 13, 2021
1 parent f8ecd32 commit c49afe7
Show file tree
Hide file tree
Showing 14 changed files with 465 additions and 114 deletions.
13 changes: 13 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
<version>${thymeleaf.extras.version}</version>
</dependency>

<!--Test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand All @@ -122,6 +123,18 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>${springframework.security.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>

<!--Only use during development-->
<!--<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;

import static de.webalf.slotbot.constant.AuthorizationCheckValues.GUILD;
import static de.webalf.slotbot.constant.AuthorizationCheckValues.ROLE_PREFIX;
import static de.webalf.slotbot.util.permissions.PermissionHelper.buildGuildAuthenticationWithPrefix;

/**
* @author Alf
Expand Down Expand Up @@ -67,6 +68,9 @@ protected void doFilterInternal(HttpServletRequest request, @NonNull HttpServlet

private Set<GrantedAuthority> mapAuthorities(@NotBlank String token) throws ForbiddenException {
final ApiToken apiToken = tokenAuthProvider.getApiToken(token);
return Collections.singleton(new SimpleGrantedAuthority(ROLE_PREFIX + apiToken.getType().name()));
final String tokenTypeName = apiToken.getType().name();
return Set.of(new SimpleGrantedAuthority(ROLE_PREFIX + tokenTypeName),
new SimpleGrantedAuthority(buildGuildAuthenticationWithPrefix(tokenTypeName, apiToken.getGuild())),
new SimpleGrantedAuthority(buildGuildAuthenticationWithPrefix(GUILD, apiToken.getGuild())));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
@Value
public class AuthorizationCheckValues {
public static final String ROLE_PREFIX = "ROLE_";
public static final String GUILD = "GUILD";

public static final String HAS_ROLE = "hasRole('";
public static final String HAS_ANY_ROLE = "hasAnyRole('";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
import javax.validation.Valid;

import static de.webalf.slotbot.constant.Urls.API;
import static de.webalf.slotbot.util.permissions.ApiPermissionHelper.HAS_READ_PUBLIC_PERMISSION;
import static de.webalf.slotbot.util.permissions.ApiPermissionHelper.HAS_WRITE_PERMISSION;
import static de.webalf.slotbot.util.EventUtils.assertApiWriteAccess;
import static de.webalf.slotbot.util.permissions.ApiPermissionHelper.HAS_POTENTIAL_READ_PUBLIC_PERMISSION;
import static de.webalf.slotbot.util.permissions.ApiPermissionHelper.HAS_POTENTIAL_WRITE_PERMISSION;

/**
* @author Alf
Expand All @@ -28,24 +29,26 @@ public class EventApiController {
private final EventService eventService;

@GetMapping("/{id}")
@PreAuthorize(HAS_READ_PUBLIC_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_READ_PUBLIC_PERMISSION)
public EventApiDto getEvent(@PathVariable(value = "id") long eventId) {
log.trace("getEvent: " + eventId);
return EventApiAssembler.toDto(eventService.findByIdForApi(eventId));
}

@PostMapping
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public EventApiDto postEvent(@Valid @RequestBody EventDto event) {
log.trace("postEvent: " + event.getName());
assertApiWriteAccess(event);
return EventApiAssembler.toDto(eventService.createEvent(event));
}

@PutMapping("/{id}")
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public EventApiDto updateEvent(@PathVariable(value = "id") long eventId, @RequestBody EventDto event) {
log.trace("updateEvent: " + event.getName());
event.setId(eventId);
assertApiWriteAccess(eventService.findById(eventId));
return EventApiAssembler.toDto(eventService.updateEvent(event));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import org.springframework.web.bind.annotation.RestController;

import static de.webalf.slotbot.constant.Urls.API;
import static de.webalf.slotbot.util.permissions.ApiPermissionHelper.HAS_READ_PUBLIC_PERMISSION;
import static de.webalf.slotbot.util.permissions.ApiPermissionHelper.HAS_POTENTIAL_READ_PUBLIC_PERMISSION;

/**
* @author Alf
Expand All @@ -28,7 +28,7 @@ public class EventApiViewDtoController {
private final EventApiAssembler eventApiAssembler;

@GetMapping("/{id}")
@PreAuthorize(HAS_READ_PUBLIC_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_READ_PUBLIC_PERMISSION)
public EventApiViewDto getEventView(@PathVariable(value = "id") long eventId) {
log.trace("getEventView: " + eventId);
return eventApiAssembler.toViewDto(eventService.findByIdForApi(eventId));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import de.webalf.slotbot.assembler.SlotAssembler;
import de.webalf.slotbot.assembler.api.EventApiAssembler;
import de.webalf.slotbot.model.Event;
import de.webalf.slotbot.model.dtos.SlotDto;
import de.webalf.slotbot.model.dtos.SquadDto;
import de.webalf.slotbot.model.dtos.UserDto;
Expand All @@ -17,9 +18,10 @@
import java.util.List;

import static de.webalf.slotbot.constant.Urls.API;
import static de.webalf.slotbot.util.EventUtils.assertApiAccessAllowed;
import static de.webalf.slotbot.util.permissions.ApiPermissionHelper.HAS_READ_PUBLIC_PERMISSION;
import static de.webalf.slotbot.util.permissions.ApiPermissionHelper.HAS_WRITE_PERMISSION;
import static de.webalf.slotbot.util.EventUtils.assertApiReadAccess;
import static de.webalf.slotbot.util.EventUtils.assertApiWriteAccess;
import static de.webalf.slotbot.util.permissions.ApiPermissionHelper.HAS_POTENTIAL_READ_PUBLIC_PERMISSION;
import static de.webalf.slotbot.util.permissions.ApiPermissionHelper.HAS_POTENTIAL_WRITE_PERMISSION;

/**
* Every action that can be performed in an event in a channel
Expand All @@ -35,106 +37,126 @@ public class EventChannelApiController {
private final EventService eventService;

@GetMapping
@PreAuthorize(HAS_READ_PUBLIC_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_READ_PUBLIC_PERMISSION)
public EventApiDto getEventByChannelId(@PathVariable(value = "channelId") long channel) {
log.trace("getEventByChannelId: " + channel);
final EventApiDto eventApiDto = EventApiAssembler.toDto(eventService.findByChannel(channel));

assertApiAccessAllowed(eventApiDto);

assertApiReadAccess(eventApiDto);
return eventApiDto;
}

@DeleteMapping
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public void deleteEventByChannelId(@PathVariable(value = "channelId") long channel) {
log.trace("deleteEventByChannelId: " + channel);
eventService.deleteEvent(channel);
final Event event = eventService.findByChannel(channel);
assertApiWriteAccess(event);
eventService.deleteEvent(event);
}

@PostMapping("/slot/{slotNumber}")
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public EventApiDto postSlot(@PathVariable(value = "channelId") long channel,
@PathVariable(value = "slotNumber") int slotNumber,
@RequestBody UserDto userDto) {
log.trace("postSlot: " + channel + " " + slotNumber + " " + userDto.getId());
return EventApiAssembler.toDto(eventService.slot(channel, slotNumber, userDto));
final Event event = eventService.findByChannel(channel);
assertApiWriteAccess(event);
return EventApiAssembler.toDto(eventService.slot(event, slotNumber, userDto));
}

@PostMapping("/unslot")
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public EventApiDto postUnslot(@PathVariable(value = "channelId") long channel,
@RequestBody UserDto userDto) {
log.trace("postUnslot: " + channel + " " + userDto.getId());
return EventApiAssembler.toDto(eventService.unslot(channel, userDto));
final Event event = eventService.findByChannel(channel);
assertApiWriteAccess(event);
return EventApiAssembler.toDto(eventService.unslot(event, userDto));
}

@PostMapping("/unslot/{slotNumber}")
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public EventRecipientApiDto postUnslotSlot(@PathVariable(value = "channelId") long channel,
@PathVariable(value = "slotNumber") int slotNumber) {
log.trace("postUnslotSlot: " + channel + " " + slotNumber);
return eventService.unslot(channel, slotNumber);
final Event event = eventService.findByChannel(channel);
assertApiWriteAccess(event);
return eventService.unslot(event, slotNumber);
}

@PutMapping("/prepareSwap")
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public List<SlotDto> getSwapSlots(@PathVariable(value = "channelId") long channel,
@RequestBody List<UserDto> userDtos) {
log.trace("getSwapSlots: " + channel);
return SlotAssembler.toDtoList(eventService.findSwapSlots(channel, userDtos));
final Event event = eventService.findByChannel(channel);
assertApiWriteAccess(event);
return SlotAssembler.toDtoList(eventService.findSwapSlots(event, userDtos));
}

@PutMapping("/prepareSwap/{slotNumber}")
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public List<SlotDto> getSwapSlots(@PathVariable(value = "channelId") long channel,
@PathVariable(value = "slotNumber") int slotNumber,
@RequestBody UserDto userDto) {
log.trace("getSwapSlots: " + channel + " SlotNumber: " + slotNumber + " user: " + userDto.getId());
return SlotAssembler.toDtoList(eventService.findSwapSlots(channel, slotNumber, userDto));
final Event event = eventService.findByChannel(channel);
assertApiWriteAccess(event);
return SlotAssembler.toDtoList(eventService.findSwapSlots(event, slotNumber, userDto));
}

@PutMapping("/blockSlot/{slotNumber}")
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public EventApiDto putBlockSlot(@PathVariable(value = "channelId") long channel,
@PathVariable(value = "slotNumber") int slotNumber,
@RequestBody(required = false) String replacementName) {
log.trace("putBlockSlot: " + channel + " " + slotNumber + " " + replacementName);
return EventApiAssembler.toDto(eventService.blockSlot(channel, slotNumber, replacementName));
final Event event = eventService.findByChannel(channel);
assertApiWriteAccess(event);
return EventApiAssembler.toDto(eventService.blockSlot(event, slotNumber, replacementName));
}

@PutMapping("/renameSquad/{squadPosition}")
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public EventApiDto putRenameSquad(@PathVariable(value = "channelId") long channel,
@PathVariable(value = "squadPosition") int squadPosition,
@RequestBody SquadDto squadDto) {
log.trace("putRenameSquad: " + channel + " " + squadPosition);
return EventApiAssembler.toDto(eventService.renameSquad(channel, squadPosition, squadDto.getName()));
final Event event = eventService.findByChannel(channel);
assertApiWriteAccess(event);
return EventApiAssembler.toDto(eventService.renameSquad(event, squadPosition, squadDto.getName()));
}

@PostMapping("/addSlot/{squadNumber}")
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public EventApiDto postAddSlot(@PathVariable(value = "channelId") long channel,
@PathVariable(value = "squadNumber") int squadNumber,
@RequestBody SlotDto slotDto) {
log.trace("postAddSlot: " + channel + " " + squadNumber + " " + slotDto.getNumber());
return EventApiAssembler.toDto(eventService.addSlot(channel, squadNumber, slotDto));
final Event event = eventService.findByChannel(channel);
assertApiWriteAccess(event);
return EventApiAssembler.toDto(eventService.addSlot(event, squadNumber, slotDto));
}

@DeleteMapping("/delSlot/{slotNumber}")
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public EventApiDto deleteSlot(@PathVariable(value = "channelId") long channel,
@PathVariable(value = "slotNumber") int slotNumber) {
log.trace("deleteSlot: " + channel + " " + slotNumber);
return EventApiAssembler.toDto(eventService.deleteSlot(channel, slotNumber));
final Event event = eventService.findByChannel(channel);
assertApiWriteAccess(event);
return EventApiAssembler.toDto(eventService.deleteSlot(event, slotNumber));
}

@PutMapping("/renameSlot/{slotNumber}")
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public EventApiDto putRenameSlot(@PathVariable(value = "channelId") long channel,
@PathVariable(value = "slotNumber") int slotNumber,
@RequestBody SlotDto slotDto) {
log.trace("putRenameSlot: " + channel + " " + slotNumber);
final Event event = eventService.findByChannel(channel);
assertApiWriteAccess(event);
return EventApiAssembler.toDto(eventService.renameSlot(channel, slotNumber, slotDto.getName()));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package de.webalf.slotbot.controller.api;

import de.webalf.slotbot.assembler.api.EventApiAssembler;
import de.webalf.slotbot.exception.ForbiddenException;
import de.webalf.slotbot.model.dtos.SlotDto;
import de.webalf.slotbot.model.dtos.api.EventApiDto;
import de.webalf.slotbot.service.SlotService;
Expand All @@ -16,7 +16,7 @@
import java.util.List;

import static de.webalf.slotbot.constant.Urls.API;
import static de.webalf.slotbot.util.permissions.ApiPermissionHelper.HAS_WRITE_PERMISSION;
import static de.webalf.slotbot.util.permissions.ApiPermissionHelper.HAS_POTENTIAL_WRITE_PERMISSION;

/**
* @author Alf
Expand All @@ -30,8 +30,10 @@ public class SlotApiController {
private final SlotService slotService;

@PutMapping("/swap")
@PreAuthorize(HAS_WRITE_PERMISSION)
@PreAuthorize(HAS_POTENTIAL_WRITE_PERMISSION)
public EventApiDto putSwap(@RequestBody List<SlotDto> slots) {
return EventApiAssembler.toDto(slotService.swap(slots));
throw new ForbiddenException("Not yet implemented");
//TODO permission check
// return EventApiAssembler.toDto(slotService.swap(slots));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public class ApiToken {
@NotBlank
private ApiTokenType type;

@Column(name = "api_token_guild", nullable = false, updatable = false)
private long guild;

@Column(name = "api_token_comment")
private String comment;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,27 @@

import lombok.Value;

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

import static de.webalf.slotbot.constant.AuthorizationCheckValues.ROLE_PREFIX;

/**
* @author Alf
* @since 06.03.2021
*/
public enum ApiTokenType {
READ_PUBLIC, //Can read all public available data
READ, //Can read all data
ADMIN, //Administrative endpoints
WRITE, //Can write all data
ADMIN; //Administrative endpoints
READ, //Can read all data
READ_PUBLIC; //Can read all public available data

public Set<ApiTokenType> getAuthorizedTokenTypes() {
final ApiTokenType[] apiTokenTypes = ApiTokenType.values();
final int i = Arrays.asList(apiTokenTypes).indexOf(this);
return Arrays.stream(apiTokenTypes).limit(i + 1).collect(Collectors.toUnmodifiableSet());
}

@Value
public static class TypeRoleNames { //These static strings are needed for the PreAuthorize annotation. They must be synchronous to the enums above.
Expand Down

0 comments on commit c49afe7

Please sign in to comment.