Skip to content

Commit

Permalink
fix: #185 simplification of authorization
Browse files Browse the repository at this point in the history
  • Loading branch information
KartVen committed Nov 18, 2024
1 parent 1b97824 commit 539bdb7
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 67 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
package pl.sknikod.kodemyauth.configuration;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.zalando.logbook.spring.LogbookClientHttpRequestInterceptor;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.util.OAuth2RestTemplate;
Expand All @@ -22,16 +17,31 @@
@Configuration
@Slf4j
public class WebConfiguration {

@Bean
public BufferingClientHttpRequestFactory bufferingClientHttpRequestFactory() {
var requestFactory = new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().build());
return new BufferingClientHttpRequestFactory(requestFactory);
}

@Bean
@LoadBalanced
public RestTemplate restTemplate(
RestTemplateBuilder restTemplateBuilder, LogbookClientHttpRequestInterceptor logbookInterceptor
RestTemplateBuilder restTemplateBuilder,
LogbookClientHttpRequestInterceptor logbookInterceptor
) {
restTemplateBuilder.requestFactory(() -> {
var requestFactory = new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().build());
return new BufferingClientHttpRequestFactory(requestFactory);
});
restTemplateBuilder.requestFactory(this::bufferingClientHttpRequestFactory);
restTemplateBuilder.additionalInterceptors(Collections.singletonList(logbookInterceptor));
return restTemplateBuilder.build();
}

@Bean
public OAuth2RestTemplate oAuth2RestTemplate(
RestTemplateBuilder restTemplateBuilder,
LogbookClientHttpRequestInterceptor logbookInterceptor
) {
restTemplateBuilder.requestFactory(this::bufferingClientHttpRequestFactory);
restTemplateBuilder.additionalInterceptors(Collections.singletonList(logbookInterceptor));
return new OAuth2RestTemplate(restTemplateBuilder.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2Provider;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor.OAuth2Provider;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
import pl.sknikod.kodemyauth.infrastructure.database.Role;
import pl.sknikod.kodemyauth.infrastructure.database.RoleRepository;
import pl.sknikod.kodemyauth.infrastructure.database.User;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2Provider;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2ProviderResult;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor.OAuth2Provider;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor.OAuth2ProcessorResult;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.util.OAuth2UserPrincipal;
import pl.sknikod.kodemyauth.infrastructure.store.UserStore;

Expand All @@ -38,7 +38,7 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic
.orElse(null);
}

private Optional<OAuth2ProviderResult> retrieveUser(OAuth2UserRequest userRequest, Iterator<OAuth2Provider> iterator) {
private Optional<OAuth2ProcessorResult> retrieveUser(OAuth2UserRequest userRequest, Iterator<OAuth2Provider> iterator) {
if (!iterator.hasNext()) {
log.info("No processable provider for registration ID: {}", userRequest.getClientRegistration().getRegistrationId());
return Optional.empty();
Expand All @@ -51,17 +51,17 @@ private Optional<OAuth2ProviderResult> retrieveUser(OAuth2UserRequest userReques
return retrieveUser(userRequest, iterator); // check another one
}

private Tuple2<User, OAuth2ProviderResult> createOrLoadUser(OAuth2ProviderResult providerUser) {
private Tuple2<User, OAuth2ProcessorResult> createOrLoadUser(OAuth2ProcessorResult providerUser) {
return userStore.findByProviderUser(providerUser)
.fold(unused -> Tuple.of(this.createNewUser(providerUser), providerUser), user -> Tuple.of(user, providerUser));
}

private User createNewUser(OAuth2ProviderResult providerUser) {
private User createNewUser(OAuth2ProcessorResult providerUser) {
return userStore.save(providerUser)
.orElse(null);
}

private OAuth2UserPrincipal toUserPrincipal(Tuple2<User, OAuth2ProviderResult> userTuple2) {
private OAuth2UserPrincipal toUserPrincipal(Tuple2<User, OAuth2ProcessorResult> userTuple2) {
return Try.of(() -> roleRepository.findById(userTuple2._1.getRole().getId()))
.filter(Optional::isPresent)
.map(Optional::get)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider;
package pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor;

import io.vavr.control.Try;
import lombok.NonNull;
Expand All @@ -12,18 +12,19 @@

@RequiredArgsConstructor
@Slf4j
public abstract class OAuth2ProviderSuperclass {
public abstract class OAuth2Processor {
protected final OAuth2RestTemplate oAuth2RestTemplate;
private final Map<String, Object> attributes = new HashMap<>();
private boolean isInitialized = false;

public abstract OAuth2ProcessorResult process(OAuth2UserRequest userRequest);

protected Map<String, Object> getAttributes(@NonNull OAuth2UserRequest userRequest) {
if (!isInitialized) {
Try.of(() -> this.oAuth2RestTemplate.exchange(userRequest).getBody())
.onSuccess(attrs -> log.info("Successfully retrieved {} user attributes", attrs.size()))
.peek(this.attributes::putAll);
this.isInitialized = true;
}
Try.of(() -> this.oAuth2RestTemplate.exchange(userRequest).getBody())
.onSuccess(attrs -> log.info("Successfully retrieved {} user attributes", attrs.size()))
.peek(m -> {
this.attributes.put("registration_id", userRequest.getClientRegistration().getRegistrationId());
this.attributes.putAll(m);
});
return attributes;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider;
package pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor;

import lombok.AllArgsConstructor;
import lombok.Getter;
Expand All @@ -7,7 +7,7 @@

@Getter
@AllArgsConstructor
public abstract class OAuth2ProviderResult {
public abstract class OAuth2ProcessorResult {
protected final Map<String, Object> attributes;

public abstract String getRegistrationId();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider;
package pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor;

import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;

public interface OAuth2Provider {
String getRegistrationId();
boolean isApply(String registrationId);
OAuth2ProviderResult retrieve(OAuth2UserRequest userRequest);
OAuth2ProcessorResult retrieve(OAuth2UserRequest userRequest);
}
Original file line number Diff line number Diff line change
@@ -1,45 +1,28 @@
package pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.github;
package pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor.github;

import io.vavr.control.Try;
import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.stereotype.Component;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2Provider;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2ProviderResult;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2ProviderSuperclass;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor.OAuth2Processor;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor.OAuth2ProcessorResult;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.util.OAuth2RestTemplate;

import java.util.List;
import java.util.Map;

@Component
@Slf4j
public class GithubOAuth2Provider extends OAuth2ProviderSuperclass implements OAuth2Provider {
private static final String REGISTRATION_ID = "github";

public GithubOAuth2Provider(OAuth2RestTemplate oAuth2RestTemplate) {
public class GithubOAuth2Processor extends OAuth2Processor {
public GithubOAuth2Processor(OAuth2RestTemplate oAuth2RestTemplate) {
super(oAuth2RestTemplate);
}

@Override
public String getRegistrationId() {
return REGISTRATION_ID;
}

@Override
public boolean isApply(String registrationId) {
return getRegistrationId().equals(registrationId);
}

@Override
public OAuth2ProviderResult retrieve(OAuth2UserRequest userRequest) {
public OAuth2ProcessorResult process(OAuth2UserRequest userRequest) {
Map<String, Object> attributes = super.getAttributes(userRequest);
attributes.put("registrationId", REGISTRATION_ID);
fixEmailNull(attributes, userRequest);
return new GithubOAuth2ProviderResult(attributes);
return new GithubOAuth2ProcessorResult(attributes);
}

private void fixEmailNull(Map<String, Object> attributes, OAuth2UserRequest userRequest) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.github;
package pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor.github;

import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2ProviderResult;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor.OAuth2ProcessorResult;

import java.util.Map;

public class GithubOAuth2ProviderResult extends OAuth2ProviderResult {
public GithubOAuth2ProviderResult(Map<String, Object> attributes) {
public class GithubOAuth2ProcessorResult extends OAuth2ProcessorResult {
public GithubOAuth2ProcessorResult(Map<String, Object> attributes) {
super(attributes);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor.github;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.stereotype.Component;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor.OAuth2Provider;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor.OAuth2ProcessorResult;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.util.OAuth2RestTemplate;

@Component
@Slf4j
@RequiredArgsConstructor
public class GithubOAuth2Provider implements OAuth2Provider {
private static final String REGISTRATION_ID = "github";
private final OAuth2RestTemplate oAuth2RestTemplate;

@Override
public String getRegistrationId() {
return REGISTRATION_ID;
}

@Override
public boolean isApply(String registrationId) {
return getRegistrationId().equals(registrationId);
}

@Override
public OAuth2ProcessorResult retrieve(OAuth2UserRequest userRequest) {
return new GithubOAuth2Processor(oAuth2RestTemplate).process(userRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import java.util.Collections;
import java.util.Map;

@Component
@RequiredArgsConstructor
public class OAuth2RestTemplate {
private final RestTemplate restTemplate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import org.springframework.stereotype.Component;
import pl.sknikod.kodemyauth.configuration.SecurityConfiguration;
import pl.sknikod.kodemyauth.infrastructure.database.*;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2ProviderResult;
import pl.sknikod.kodemyauth.infrastructure.module.oauth2.processor.OAuth2ProcessorResult;
import pl.sknikod.kodemycommons.exception.InternalError500Exception;
import pl.sknikod.kodemycommons.exception.NotFound404Exception;
import pl.sknikod.kodemycommons.exception.content.ExceptionMsgPattern;
Expand All @@ -26,15 +26,15 @@ public class UserStore {
private final RoleRepository roleRepository;
private final SecurityConfiguration.RoleProperties roleProperties;

public Optional<User> save(OAuth2ProviderResult providerUser) {
public Optional<User> save(OAuth2ProcessorResult result) {
return this.fetchRole(roleProperties.getPrimary())
.map(role -> new User(
providerUser.getUsername(), providerUser.getEmail(),
providerUser.getPhoto(), role))
result.getUsername(), result.getEmail(),
result.getPhoto(), role))
.map(user -> {
var provider = new Provider(
providerUser.getPrincipalId(), providerUser.getRegistrationId(),
providerUser.getEmail(), providerUser.getPhoto(), user
result.getPrincipalId(), result.getRegistrationId(),
result.getEmail(), result.getPhoto(), user
);
user.setProviders(Set.of(provider));
return user;
Expand All @@ -52,9 +52,9 @@ private Try<Role> fetchRole(String roleName) {
.onFailure(th -> log.error(th.getMessage()));
}

public Try<User> findByProviderUser(OAuth2ProviderResult providerUser) {
public Try<User> findByProviderUser(OAuth2ProcessorResult result) {
return Option.of(userRepository.findUserByPrincipalIdAndAuthProvider(
providerUser.getPrincipalId(), providerUser.getRegistrationId()
result.getPrincipalId(), result.getRegistrationId()
))
.toTry(() -> new NotFound404Exception(ExceptionMsgPattern.ENTITY_NOT_FOUND, User.class));
}
Expand Down

0 comments on commit 539bdb7

Please sign in to comment.