diff --git a/client-impl/src/main/java/ru/dragonestia/picker/api/impl/RoomPickerClient.java b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/RoomPickerClient.java index c5febad..cbe29c8 100644 --- a/client-impl/src/main/java/ru/dragonestia/picker/api/impl/RoomPickerClient.java +++ b/client-impl/src/main/java/ru/dragonestia/picker/api/impl/RoomPickerClient.java @@ -63,6 +63,10 @@ public class RoomPickerClient { return userRepository; } + public @NotNull AccountRepository getAccountRepository() { + return accountRepository; + } + public @NotNull RoomPickerInfoResponse getServerInfo() { return restTemplate.query("/info", HttpMethod.GET, RoomPickerInfoResponse.class, params -> {}); } diff --git a/control-panel/build.gradle b/control-panel/build.gradle index 3f14ebe..18454c9 100644 --- a/control-panel/build.gradle +++ b/control-panel/build.gradle @@ -31,6 +31,8 @@ dependencies { implementation project(":client-impl") implementation 'com.vaadin:vaadin-spring-boot-starter' + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.jetbrains:annotations:24.1.0' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/config/RoomPickerConfig.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/config/RoomPickerConfig.java index 81d9913..6b52ccd 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/config/RoomPickerConfig.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/config/RoomPickerConfig.java @@ -5,6 +5,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import ru.dragonestia.picker.api.impl.RoomPickerClient; import ru.dragonestia.picker.cp.annotation.ServerURL; +import ru.dragonestia.picker.cp.model.Account; +import ru.dragonestia.picker.cp.model.provider.AccountProvider; @Configuration public class RoomPickerConfig { @@ -12,6 +14,12 @@ public class RoomPickerConfig { @Value("${ROOMPICKER_HOST_URL:http://localhost:8080}") private String serverUrl; + @Value("${ROOMPICKER_ADMIN_USERNAME:admin}") + private String adminUsername; + + @Value("${ROOMPICKER_ADMIN_PASSWORD:qwerty123}") + private String adminPassword; + @ServerURL @Bean String severUrl() { @@ -19,7 +27,12 @@ public class RoomPickerConfig { } @Bean - RoomPickerClient roomPickerClient() { + RoomPickerClient adminClient() { return new RoomPickerClient(serverUrl, "admin", "qwerty123"); } + + @Bean + AccountProvider accountProvider() { + return response -> new Account(response, new RoomPickerClient(serverUrl, response.getUsername(), response.getPassword())); + } } 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 new file mode 100644 index 0000000..75b7b50 --- /dev/null +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/config/SecurityConfig.java @@ -0,0 +1,34 @@ +package ru.dragonestia.picker.cp.config; + +import com.vaadin.flow.spring.security.VaadinWebSecurity; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; +import ru.dragonestia.picker.api.impl.RoomPickerClient; +import ru.dragonestia.picker.cp.model.provider.AccountProvider; +import ru.dragonestia.picker.cp.service.AccountService; + +@Configuration +public class SecurityConfig extends VaadinWebSecurity { + + @Bean + PasswordEncoder passwordEncoder() { + return new PasswordEncoder() { + @Override + public String encode(CharSequence rawPassword) { + return rawPassword.toString(); + } + + @Override + public boolean matches(CharSequence rawPassword, String encodedPassword) { + return rawPassword.toString().equals(encodedPassword); + } + }; + } + + @Bean + UserDetailsService userDetailsService(RoomPickerClient adminClient, AccountProvider accountProvider) { + return new AccountService(adminClient, accountProvider); + } +} 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 new file mode 100644 index 0000000..0790f70 --- /dev/null +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/model/Account.java @@ -0,0 +1,73 @@ +package ru.dragonestia.picker.cp.model; + +import org.jetbrains.annotations.NotNull; +import org.springframework.security.core.userdetails.UserDetails; +import ru.dragonestia.picker.api.impl.RoomPickerClient; +import ru.dragonestia.picker.api.model.account.IAccount; +import ru.dragonestia.picker.api.model.account.ResponseAccount; + +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; + +public class Account implements IAccount, UserDetails { + + private final ResponseAccount original; + private final RoomPickerClient client; + private final Set permissions; + + public Account(ResponseAccount original, RoomPickerClient client) { + this.original = original; + this.client = client; + permissions = original.getPermissions().stream().map(Permission::new).collect(Collectors.toSet()); + } + + public @NotNull RoomPickerClient getClient() { + return client; + } + + @Override + public Collection getAuthorities() { + return permissions; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return !original.isLocked(); + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public @NotNull String getUsername() { + return original.getUsername(); + } + + @Override + public @NotNull String getPassword() { + return original.getPassword(); + } + + @Override + public @NotNull Set getPermissions() { + return original.getPermissions(); + } + + @Override + public boolean isLocked() { + return original.isLocked(); + } +} diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/model/Permission.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/model/Permission.java new file mode 100644 index 0000000..97499ff --- /dev/null +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/model/Permission.java @@ -0,0 +1,18 @@ +package ru.dragonestia.picker.cp.model; + +import com.github.javaparser.quality.NotNull; +import org.springframework.security.core.GrantedAuthority; + +public class Permission implements GrantedAuthority { + + private final String authority; + + public Permission(@NotNull String authority) { + this.authority = authority; + } + + @Override + public String getAuthority() { + return authority; + } +} diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/model/provider/AccountProvider.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/model/provider/AccountProvider.java new file mode 100644 index 0000000..1e6fd60 --- /dev/null +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/model/provider/AccountProvider.java @@ -0,0 +1,10 @@ +package ru.dragonestia.picker.cp.model.provider; + +import org.jetbrains.annotations.NotNull; +import ru.dragonestia.picker.api.model.account.ResponseAccount; +import ru.dragonestia.picker.cp.model.Account; + +public interface AccountProvider { + + @NotNull Account provide(@NotNull ResponseAccount responseAccount); +} diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/service/AccountService.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/service/AccountService.java new file mode 100644 index 0000000..82e1de6 --- /dev/null +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/service/AccountService.java @@ -0,0 +1,25 @@ +package ru.dragonestia.picker.cp.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; +import ru.dragonestia.picker.api.impl.RoomPickerClient; +import ru.dragonestia.picker.cp.model.Account; +import ru.dragonestia.picker.cp.model.provider.AccountProvider; + +@Service +@RequiredArgsConstructor +public class AccountService implements UserDetailsService { + + private final RoomPickerClient adminClient; + private final AccountProvider accountProvider; + + @Override + public Account loadUserByUsername(String username) throws UsernameNotFoundException { + var response = adminClient.getAccountRepository().findAccountByUsername(username) + .orElseThrow(() -> new UsernameNotFoundException(username)); + + return accountProvider.provide(response); + } +}