From b48b375e4e04346acc689cd1f577f8226a42b202 Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Mon, 25 Mar 2024 17:04:16 +0700 Subject: [PATCH] Implemented authorisation --- .../AccountDoesNotExistsException.java | 39 +++++++++++++++++++ .../api/exception/ExceptionFactory.java | 1 + .../repository/AccountRepositoryImpl.java | 9 ++++- config/prometheus.yml | 2 +- .../picker/cp/config/SecurityConfig.java | 12 +++--- .../cp/error/ApplicationErrorHandler.java | 8 ++++ .../dragonestia/picker/cp/model/Account.java | 2 +- .../dragonestia/picker/cp/page/HomePage.java | 29 -------------- .../dragonestia/picker/cp/page/LoginPage.java | 2 + .../picker/cp/page/MainLayout.java | 7 +--- .../picker/cp/page/NodeDetailsPage.java | 2 + .../dragonestia/picker/cp/page/NodesPage.java | 11 +++--- .../picker/cp/page/RoomDetailsPage.java | 5 ++- .../picker/cp/page/UserDetailsPage.java | 11 ++---- .../picker/cp/page/UserSearchPage.java | 2 + .../page/plug/NotEnoughPermissionsPlug.java | 24 ++++++++++++ docker-compose.yml | 9 +++++ .../picker/controller/AccountsController.java | 15 +++++-- .../ExceptionHandlerController.java | 5 +++ .../dragonestia/picker/model/Permission.java | 2 +- .../picker/service/AccountService.java | 4 ++ .../service/impl/AccountServiceImpl.java | 5 ++- 22 files changed, 142 insertions(+), 64 deletions(-) create mode 100644 client-api/src/main/java/ru/dragonestia/picker/api/exception/AccountDoesNotExistsException.java delete mode 100644 control-panel/src/main/java/ru/dragonestia/picker/cp/page/HomePage.java create mode 100644 control-panel/src/main/java/ru/dragonestia/picker/cp/page/plug/NotEnoughPermissionsPlug.java diff --git a/client-api/src/main/java/ru/dragonestia/picker/api/exception/AccountDoesNotExistsException.java b/client-api/src/main/java/ru/dragonestia/picker/api/exception/AccountDoesNotExistsException.java new file mode 100644 index 0000000..5db5678 --- /dev/null +++ b/client-api/src/main/java/ru/dragonestia/picker/api/exception/AccountDoesNotExistsException.java @@ -0,0 +1,39 @@ +package ru.dragonestia.picker.api.exception; + +import ru.dragonestia.picker.api.repository.response.ErrorResponse; + +import java.util.Map; + +public class AccountDoesNotExistsException extends ApiException { + + public static final String ERROR_ID = "err.account.does_not_exists"; + + private final String accountId; + + public AccountDoesNotExistsException(String accountId) { + this.accountId = accountId; + } + + public AccountDoesNotExistsException(ErrorResponse errorResponse) { + this(errorResponse.details().get("accountId")); + } + + public String getAccountId() { + return accountId; + } + + @Override + public String getErrorId() { + return ERROR_ID; + } + + @Override + public String getMessage() { + return "Account with id '" + accountId + "' does not exists"; + } + + @Override + public void appendDetailsToErrorResponse(Map details) { + details.put("accountId", accountId); + } +} diff --git a/client-api/src/main/java/ru/dragonestia/picker/api/exception/ExceptionFactory.java b/client-api/src/main/java/ru/dragonestia/picker/api/exception/ExceptionFactory.java index 870efcf..b9ef5d5 100644 --- a/client-api/src/main/java/ru/dragonestia/picker/api/exception/ExceptionFactory.java +++ b/client-api/src/main/java/ru/dragonestia/picker/api/exception/ExceptionFactory.java @@ -25,6 +25,7 @@ public class ExceptionFactory { factory.put(RoomAreFullException.ERROR_ID, RoomAreFullException::new); factory.put(RoomNotFoundException.ERROR_ID, RoomNotFoundException::new); factory.put(NotPersistedNodeException.ERROR_ID, NotPersistedNodeException::new); + factory.put(AccountDoesNotExistsException.ERROR_ID, AccountDoesNotExistsException::new); return factory; } diff --git a/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/AccountRepositoryImpl.java b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/AccountRepositoryImpl.java index 5600ecc..29f2e24 100644 --- a/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/AccountRepositoryImpl.java +++ b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/repository/AccountRepositoryImpl.java @@ -2,8 +2,10 @@ package ru.dragonestia.picker.api.impl.repository; import org.jetbrains.annotations.ApiStatus.Internal; import org.jetbrains.annotations.NotNull; +import ru.dragonestia.picker.api.exception.AccountDoesNotExistsException; import ru.dragonestia.picker.api.impl.RoomPickerClient; import ru.dragonestia.picker.api.impl.util.RestTemplate; +import ru.dragonestia.picker.api.impl.util.type.HttpMethod; import ru.dragonestia.picker.api.model.account.ResponseAccount; import ru.dragonestia.picker.api.repository.AccountRepository; @@ -20,6 +22,11 @@ public class AccountRepositoryImpl implements AccountRepository { @Override public Optional findAccountByUsername(@NotNull String username) { - throw new UnsupportedOperationException("Not implemented"); + try { + var response = rest.query("/accounts/" + username, HttpMethod.GET, ResponseAccount.class); + return Optional.of(response); + } catch (AccountDoesNotExistsException ex) { + return Optional.empty(); + } } } diff --git a/config/prometheus.yml b/config/prometheus.yml index 96eb4ce..5b1fc87 100644 --- a/config/prometheus.yml +++ b/config/prometheus.yml @@ -8,4 +8,4 @@ scrape_configs: scrape_interval: 5s metrics_path: '/actuator/prometheus' static_configs: - - targets: [ 'host.docker.internal:8080' ] + - targets: [ 'server:8080' ] diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/config/SecurityConfig.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/config/SecurityConfig.java index 64f0248..0ee91fb 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/config/SecurityConfig.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/config/SecurityConfig.java @@ -7,6 +7,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import ru.dragonestia.picker.cp.page.LoginPage; import ru.dragonestia.picker.cp.service.AccountService; @@ -39,16 +40,17 @@ public class SecurityConfig extends VaadinWebSecurity { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeHttpRequests(auth -> { - - }); - - http.formLogin(login -> { - login.successForwardUrl("/nodes"); + auth.requestMatchers(AntPathRequestMatcher.antMatcher("/static/**")).permitAll(); }); http.userDetailsService(accountService); super.configure(http); + + http.formLogin(login -> { + login.successForwardUrl("/nodes"); + login.defaultSuccessUrl("/nodes"); + }); setLoginView(http, LoginPage.class); } } diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/error/ApplicationErrorHandler.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/error/ApplicationErrorHandler.java index 90e159c..b131c5d 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/error/ApplicationErrorHandler.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/error/ApplicationErrorHandler.java @@ -6,6 +6,7 @@ import com.vaadin.flow.server.ErrorEvent; import com.vaadin.flow.server.ErrorHandler; import lombok.extern.log4j.Log4j2; import ru.dragonestia.picker.api.exception.ApiException; +import ru.dragonestia.picker.api.impl.exception.NotEnoughPermissions; import ru.dragonestia.picker.cp.component.Notifications; import java.security.InvalidParameterException; @@ -34,6 +35,13 @@ public class ApplicationErrorHandler implements ErrorHandler { return; } + if (errorEvent.getThrowable() instanceof NotEnoughPermissions) { + execute(() -> { + Notifications.error("Not enough permissions to this action"); + }); + return; + } + execute(() -> { Notifications.error("Internal server error"); }); diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/model/Account.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/model/Account.java index 0790f70..053a412 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/model/Account.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/model/Account.java @@ -19,7 +19,7 @@ public class Account implements IAccount, UserDetails { public Account(ResponseAccount original, RoomPickerClient client) { this.original = original; this.client = client; - permissions = original.getPermissions().stream().map(Permission::new).collect(Collectors.toSet()); + permissions = original.getPermissions().stream().map(permission -> new Permission("ROLE_" + permission)).collect(Collectors.toSet()); } public @NotNull RoomPickerClient getClient() { diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/HomePage.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/HomePage.java deleted file mode 100644 index 1549a5a..0000000 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/HomePage.java +++ /dev/null @@ -1,29 +0,0 @@ -package ru.dragonestia.picker.cp.page; - -import com.vaadin.flow.component.button.Button; -import com.vaadin.flow.component.html.H1; -import com.vaadin.flow.component.html.Paragraph; -import com.vaadin.flow.component.notification.Notification; -import com.vaadin.flow.component.orderedlayout.VerticalLayout; -import com.vaadin.flow.component.textfield.TextField; -import com.vaadin.flow.router.*; - -import java.awt.*; - -@Route(value = "/", layout = MainLayout.class) -public class HomePage extends VerticalLayout { - - public HomePage() { - super(); - - var field = new TextField("Some field"); - field.setRequired(true); - add(field); - - var button = new Button("Click me", e -> { - Notification.show(field.isInvalid() + ""); - }); - - add(button); - } -} diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/LoginPage.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/LoginPage.java index bdb3f7e..419797b 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/LoginPage.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/LoginPage.java @@ -7,9 +7,11 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.Route; +import com.vaadin.flow.server.auth.AnonymousAllowed; import lombok.extern.log4j.Log4j2; @Log4j2 +@AnonymousAllowed @Route("/login") public class LoginPage extends VerticalLayout implements BeforeEnterObserver { diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/MainLayout.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/MainLayout.java index acb5893..7099bab 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/MainLayout.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/MainLayout.java @@ -16,13 +16,11 @@ import ru.dragonestia.picker.cp.annotation.ServerURL; public class MainLayout extends AppLayout { - private final RoomPickerClient client; private final RoomPickerInfoResponse serverInfo; private final String serverUrl; - public MainLayout(RoomPickerClient client, @ServerURL String serverUrl) { - this.client = client; - this.serverInfo = client.getServerInfo(); + public MainLayout(RoomPickerClient adminClient, @ServerURL String serverUrl) { + this.serverInfo = adminClient.getServerInfo(); this.serverUrl = serverUrl; var toggle = new DrawerToggle(); @@ -47,7 +45,6 @@ public class MainLayout extends AppLayout { nav.addItem(new SideNavItem("Search users", UserSearchPage.class, VaadinIcon.SEARCH.create())); nav.addItem(new SideNavItem("Documentation", "https://github.com/ScarletRedMan/RoomPicker", VaadinIcon.BOOK.create())); nav.addItem(new SideNavItem("Swagger UI", serverUrl + "/api-docs-ui", VaadinIcon.CURLY_BRACKETS.create())); - nav.addItem(new SideNavItem("Sign-out", HomePage.class, VaadinIcon.SIGN_OUT.create())); return nav; } } diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/NodeDetailsPage.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/NodeDetailsPage.java index f9bdcd4..197e0dd 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/NodeDetailsPage.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/NodeDetailsPage.java @@ -8,6 +8,7 @@ import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; +import jakarta.annotation.security.PermitAll; import lombok.Getter; import lombok.RequiredArgsConstructor; import ru.dragonestia.picker.api.impl.RoomPickerClient; @@ -19,6 +20,7 @@ import ru.dragonestia.picker.cp.util.RouteParamsExtractor; @Getter @RequiredArgsConstructor +@PermitAll @PageTitle("Rooms") @Route(value = "/nodes/:nodeId", layout = MainLayout.class) public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserver { diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/NodesPage.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/NodesPage.java index cda0488..4b51b5f 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/NodesPage.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/NodesPage.java @@ -4,8 +4,8 @@ import com.vaadin.flow.component.html.Hr; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; -import lombok.Getter; -import lombok.extern.log4j.Log4j2; +import com.vaadin.flow.router.RouteAlias; +import jakarta.annotation.security.PermitAll; import org.springframework.beans.factory.annotation.Autowired; import ru.dragonestia.picker.api.exception.ApiException; import ru.dragonestia.picker.api.impl.RoomPickerClient; @@ -14,14 +14,13 @@ import ru.dragonestia.picker.cp.component.NavPath; import ru.dragonestia.picker.cp.component.NodeList; import ru.dragonestia.picker.cp.component.RegisterNode; -@Log4j2 -@Getter +@PermitAll @PageTitle("Nodes") +@RouteAlias(value = "/", layout = MainLayout.class) @Route(value = "/nodes", layout = MainLayout.class) public class NodesPage extends VerticalLayout { private final NodeRepository nodeRepository; - private final RegisterNode registerNode; private final NodeList nodeList; public NodesPage(@Autowired RoomPickerClient client) { @@ -29,7 +28,7 @@ public class NodesPage extends VerticalLayout { this.nodeRepository = client.getNodeRepository(); add(NavPath.rootNodes()); - add(registerNode = createRegisterNodeElement()); + add(createRegisterNodeElement()); add(new Hr()); add(nodeList = createNodeListElement()); } diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/RoomDetailsPage.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/RoomDetailsPage.java index b26b0ef..7368622 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/RoomDetailsPage.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/RoomDetailsPage.java @@ -13,6 +13,7 @@ import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; +import jakarta.annotation.security.PermitAll; import lombok.RequiredArgsConstructor; import ru.dragonestia.picker.api.impl.RoomPickerClient; import ru.dragonestia.picker.api.model.node.INode; @@ -31,6 +32,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; @RequiredArgsConstructor +@PermitAll @PageTitle("Room details") @Route(value = "/nodes/:nodeId/rooms/:roomId", layout = MainLayout.class) public class RoomDetailsPage extends VerticalLayout implements BeforeEnterObserver { @@ -40,7 +42,6 @@ public class RoomDetailsPage extends VerticalLayout implements BeforeEnterObserv private INode node; private ResponseRoom room; - private AddUsers addUsers; private UserList userList; private Button lockRoomButton; private VerticalLayout roomInfo; @@ -58,7 +59,7 @@ public class RoomDetailsPage extends VerticalLayout implements BeforeEnterObserv add(new H2("Room details")); printRoomDetails(); add(new Hr()); - add(addUsers = new AddUsers(room, (users, ignoreLimitation) -> appendUsers(room, users, ignoreLimitation))); + add(new AddUsers(room, (users, ignoreLimitation) -> appendUsers(room, users, ignoreLimitation))); add(new Hr()); add(new H2("Users")); add(userList = new UserList(room, client.getUserRepository())); diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/UserDetailsPage.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/UserDetailsPage.java index d376fdc..b6395e0 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/UserDetailsPage.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/UserDetailsPage.java @@ -1,6 +1,5 @@ package ru.dragonestia.picker.cp.page; -import com.vaadin.flow.component.Html; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.grid.ColumnTextAlign; @@ -12,6 +11,7 @@ import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; +import jakarta.annotation.security.PermitAll; import lombok.RequiredArgsConstructor; import ru.dragonestia.picker.api.impl.RoomPickerClient; import ru.dragonestia.picker.api.model.room.RoomDetails; @@ -21,11 +21,11 @@ import ru.dragonestia.picker.api.repository.query.user.FindRoomsLinkedWithUser; import ru.dragonestia.picker.cp.component.RefreshableTable; import ru.dragonestia.picker.cp.util.RouteParamsExtractor; -import java.util.LinkedList; import java.util.List; import java.util.Objects; @RequiredArgsConstructor +@PermitAll @PageTitle("User details") @Route(value = "/users/:userId", layout = MainLayout.class) public class UserDetailsPage extends VerticalLayout implements BeforeEnterObserver, RefreshableTable { @@ -34,7 +34,6 @@ public class UserDetailsPage extends VerticalLayout implements BeforeEnterObserv private final RouteParamsExtractor paramsExtractor; private IUser user; private Grid gridRooms; - private List cachedRooms = new LinkedList<>(); @Override public void beforeEnter(BeforeEnterEvent event) { @@ -79,13 +78,9 @@ public class UserDetailsPage extends VerticalLayout implements BeforeEnterObserv return grid; } - private Html createComponent(String defaultValue) { - return new Html("" + defaultValue + ""); - } - @Override public void refresh() { - cachedRooms = client.getUserRepository() + List cachedRooms = client.getUserRepository() .findRoomsLinkedWithUser(FindRoomsLinkedWithUser.withAllDetails(user.getIdentifierObject())); gridRooms.setItems(cachedRooms); } diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/UserSearchPage.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/UserSearchPage.java index a1d5e47..7fa2660 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/UserSearchPage.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/UserSearchPage.java @@ -13,6 +13,7 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; +import jakarta.annotation.security.PermitAll; import org.springframework.beans.factory.annotation.Autowired; import ru.dragonestia.picker.api.impl.RoomPickerClient; import ru.dragonestia.picker.api.model.user.IUser; @@ -26,6 +27,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Objects; +@PermitAll @PageTitle("Search users") @Route(value = "/users", layout = MainLayout.class) public class UserSearchPage extends VerticalLayout implements RefreshableTable { diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/plug/NotEnoughPermissionsPlug.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/plug/NotEnoughPermissionsPlug.java new file mode 100644 index 0000000..55c860e --- /dev/null +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/plug/NotEnoughPermissionsPlug.java @@ -0,0 +1,24 @@ +package ru.dragonestia.picker.cp.page.plug; + +import com.vaadin.flow.component.html.H1; +import com.vaadin.flow.component.html.Paragraph; +import com.vaadin.flow.router.BeforeEnterEvent; +import com.vaadin.flow.router.ErrorParameter; +import com.vaadin.flow.router.HasErrorParameter; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.core.userdetails.User; +import ru.dragonestia.picker.api.impl.exception.NotEnoughPermissions; + +public class NotEnoughPermissionsPlug extends ErrorPlug implements HasErrorParameter { + + @Override + public int setErrorParameter(BeforeEnterEvent event, ErrorParameter parameter) { + return render(this); + } + + public static int render(ErrorPlug plug) { + plug.add(new H1("Access denied")); + plug.add(new Paragraph("You do not have sufficient permissions to access this page")); + return HttpServletResponse.SC_FORBIDDEN; + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 316e37b..1c3f600 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,3 +17,12 @@ services: GF_SECURITY_ADMIN_PASSWORD: admin volumes: - "./appdata/grafana:/var/lib/grafana/" + + server: + image: openjdk:17-oracle + ports: + - "8080:8080" + working_dir: "/app" + volumes: + - "./appdata/server:/app" + entrypoint: "java -jar -Dspring.profiles.active='test' server.jar" diff --git a/server/src/main/java/ru/dragonestia/picker/controller/AccountsController.java b/server/src/main/java/ru/dragonestia/picker/controller/AccountsController.java index 1643c42..85040a3 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/AccountsController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/AccountsController.java @@ -1,10 +1,10 @@ package ru.dragonestia.picker.controller; import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.web.bind.annotation.*; import ru.dragonestia.picker.api.model.account.ResponseAccount; import ru.dragonestia.picker.model.Account; import ru.dragonestia.picker.service.AccountService; @@ -21,4 +21,13 @@ public class AccountsController { var account = (Account) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); return account.toResponseObject(); } + + @GetMapping("/{accountId}") + ResponseEntity findAccount(@PathVariable String accountId) { + try { + return ResponseEntity.ok(accountService.loadUserByUsername(accountId).toResponseObject()); + } catch (UsernameNotFoundException ex) { + return ResponseEntity.notFound().build(); + } + } } diff --git a/server/src/main/java/ru/dragonestia/picker/controller/ExceptionHandlerController.java b/server/src/main/java/ru/dragonestia/picker/controller/ExceptionHandlerController.java index f97d4e5..6a273ee 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/ExceptionHandlerController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/ExceptionHandlerController.java @@ -61,6 +61,11 @@ public class ExceptionHandlerController { return create(400, ex); } + @ExceptionHandler(AccountDoesNotExistsException.class) + ResponseEntity accountDoesNotExists(AccountDoesNotExistsException ex) { + return create(404, ex); + } + private ResponseEntity create(int code, ApiException ex) { var details = new HashMap(); ex.appendDetailsToErrorResponse(details); diff --git a/server/src/main/java/ru/dragonestia/picker/model/Permission.java b/server/src/main/java/ru/dragonestia/picker/model/Permission.java index c295d6e..2b485fd 100644 --- a/server/src/main/java/ru/dragonestia/picker/model/Permission.java +++ b/server/src/main/java/ru/dragonestia/picker/model/Permission.java @@ -9,6 +9,6 @@ public enum Permission implements GrantedAuthority { @Override public String getAuthority() { - return name(); + return "ROLE_" + name(); } } diff --git a/server/src/main/java/ru/dragonestia/picker/service/AccountService.java b/server/src/main/java/ru/dragonestia/picker/service/AccountService.java index f0b2bec..b71f6e9 100644 --- a/server/src/main/java/ru/dragonestia/picker/service/AccountService.java +++ b/server/src/main/java/ru/dragonestia/picker/service/AccountService.java @@ -3,6 +3,7 @@ package ru.dragonestia.picker.service; import org.jetbrains.annotations.NotNull; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import ru.dragonestia.picker.model.Account; import java.util.Collection; @@ -17,4 +18,7 @@ public interface AccountService extends UserDetailsService { @PreAuthorize("hasRole('ADMIN')") void removeAccount(@NotNull Account account); + + @Override + Account loadUserByUsername(String username) throws UsernameNotFoundException; } diff --git a/server/src/main/java/ru/dragonestia/picker/service/impl/AccountServiceImpl.java b/server/src/main/java/ru/dragonestia/picker/service/impl/AccountServiceImpl.java index 3af48e6..2ed282f 100644 --- a/server/src/main/java/ru/dragonestia/picker/service/impl/AccountServiceImpl.java +++ b/server/src/main/java/ru/dragonestia/picker/service/impl/AccountServiceImpl.java @@ -10,10 +10,11 @@ import ru.dragonestia.picker.model.Account; import ru.dragonestia.picker.model.Permission; import ru.dragonestia.picker.service.AccountService; +import java.util.Arrays; import java.util.Collection; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -26,7 +27,7 @@ public class AccountServiceImpl implements AccountService { @PostConstruct void init() { var account = createNewAccount("admin", "qwerty123"); - account.setAuthorities(Set.of(Permission.ADMIN)); + account.setAuthorities(Arrays.stream(Permission.values()).collect(Collectors.toSet())); } public @NotNull Account createNewAccount(@NotNull String username, @NotNull String password) {