From e0da261948434f508794da56bd9020bfff15807b Mon Sep 17 00:00:00 2001 From: th37rose Date: Thu, 2 May 2024 07:33:13 +0000 Subject: [PATCH 01/12] Implemented the generic Auth feature. --- .../sdk/auth/Oauth2GenericAuthConfig.java | 18 ++++ .../sdk/auth/Oauth2SimpleAuthConfig.java | 1 + .../sdk/auth/constants/AuthTypeConstants.java | 1 + .../java/org/lowcoder/sdk/util/JsonUtils.java | 6 +- .../AuthenticationController.java | 22 +++++ .../AuthenticationEndpoints.java | 18 ++++ .../oauth2/GenericOAuthProviderSource.java | 31 +++++++ .../oauth2/Oauth2AuthRequestFactory.java | 11 +-- .../oauth2/request/GenericAuthRequest.java | 91 +++++++++++++++++++ .../service/AuthenticationApiService.java | 16 ++++ .../service/AuthenticationApiServiceImpl.java | 52 +++++++++++ .../factory/AuthConfigFactoryImpl.java | 35 +++++-- .../util/AuthenticationUtils.java | 29 ++++++ 13 files changed, 314 insertions(+), 17 deletions(-) create mode 100644 server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java create mode 100644 server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/GenericOAuthProviderSource.java create mode 100644 server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/request/GenericAuthRequest.java diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java new file mode 100644 index 000000000..1f8fcd604 --- /dev/null +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java @@ -0,0 +1,18 @@ +package org.lowcoder.sdk.auth; + +import lombok.Getter; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; + +/** + * This class is for Generic Auth Provider + */ +@Getter +@SuperBuilder +@Jacksonized +public class Oauth2GenericAuthConfig extends Oauth2SimpleAuthConfig { + private String issuerUri; + private String authorizationEndpoint; + private String tokenEndpoint; + private String userInfoEndpoint; +} diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java index 25dad17a6..81d17d915 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java @@ -38,6 +38,7 @@ public String getAuthorizeUrl() { case AuthTypeConstants.GITHUB -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.GITHUB_AUTHORIZE_URL); case AuthTypeConstants.ORY -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.ORY_AUTHORIZE_URL); case AuthTypeConstants.KEYCLOAK -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.KEYCLOAK_AUTHORIZE_URL); + case AuthTypeConstants.GENERIC -> replaceAuthUrlClientIdPlaceholder(((Oauth2GenericAuthConfig)this).getAuthorizationEndpoint()); default -> null; }; } diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/constants/AuthTypeConstants.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/constants/AuthTypeConstants.java index f2d4076bd..4f7d209c9 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/constants/AuthTypeConstants.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/constants/AuthTypeConstants.java @@ -10,4 +10,5 @@ public class AuthTypeConstants { public static final String GITHUB = "GITHUB"; public static final String ORY = "ORY"; public static final String KEYCLOAK = "KEYCLOAK"; + public static final String GENERIC = "GENERIC"; } diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/util/JsonUtils.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/util/JsonUtils.java index 0c4dd861b..6c5084556 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/util/JsonUtils.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/util/JsonUtils.java @@ -13,10 +13,7 @@ import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; import jakarta.annotation.Nullable; import lombok.extern.slf4j.Slf4j; -import org.lowcoder.sdk.auth.EmailAuthConfig; -import org.lowcoder.sdk.auth.Oauth2KeycloakAuthConfig; -import org.lowcoder.sdk.auth.Oauth2OryAuthConfig; -import org.lowcoder.sdk.auth.Oauth2SimpleAuthConfig; +import org.lowcoder.sdk.auth.*; import java.nio.charset.StandardCharsets; import java.util.List; @@ -41,6 +38,7 @@ public final class JsonUtils { OBJECT_MAPPER.registerSubtypes(new NamedType(Oauth2SimpleAuthConfig.class, GOOGLE)); OBJECT_MAPPER.registerSubtypes(new NamedType(Oauth2OryAuthConfig.class, ORY)); OBJECT_MAPPER.registerSubtypes(new NamedType(Oauth2KeycloakAuthConfig.class, KEYCLOAK)); + OBJECT_MAPPER.registerSubtypes(new NamedType(Oauth2GenericAuthConfig.class, GENERIC)); } public static final JsonNode EMPTY_JSON_NODE = createObjectNode(); diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java index 81dbd09b5..89c666d9e 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java @@ -1,6 +1,7 @@ package org.lowcoder.api.authentication; import java.util.List; +import java.util.Map; import org.lowcoder.api.authentication.dto.APIKeyRequest; import org.lowcoder.api.authentication.dto.AuthConfigRequest; @@ -14,7 +15,9 @@ import org.lowcoder.domain.authentication.FindAuthConfig; import org.lowcoder.domain.user.model.APIKey; import org.lowcoder.sdk.auth.AbstractAuthConfig; +import org.lowcoder.sdk.auth.Oauth2GenericAuthConfig; import org.lowcoder.sdk.util.CookieHelper; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; @@ -128,4 +131,23 @@ public Mono>> getAllAPIKeys() { .map(ResponseView::success); } + /** + * This endpoint is to get IDP configuration + * @param issuerUri String + * @param source String + * @param sourceName String + * @param clientId String + * @param clientSecret String + * @return Oauth2GenericAuthConfig + */ + @Override + public Mono> addOAuthProvider(String issuerUri, + String source, + String sourceName, + String clientId, + String clientSecret) { + return authenticationApiService.fetchAndParseConfiguration(issuerUri, source, sourceName, clientId, clientSecret) + .map(ResponseView::success); + } + } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationEndpoints.java index d66e252ae..1668fbfe4 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationEndpoints.java @@ -1,6 +1,7 @@ package org.lowcoder.api.authentication; import java.util.List; +import java.util.Map; import org.lowcoder.api.authentication.dto.APIKeyRequest; import org.lowcoder.api.authentication.dto.AuthConfigRequest; @@ -11,8 +12,10 @@ import org.lowcoder.domain.user.model.APIKey; import org.lowcoder.infra.constant.NewUrl; import org.lowcoder.sdk.auth.AbstractAuthConfig; +import org.lowcoder.sdk.auth.Oauth2GenericAuthConfig; import org.lowcoder.sdk.config.SerializeConfig.JsonViews; import org.lowcoder.sdk.constants.AuthSourceConstants; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -160,4 +163,19 @@ public Mono> linkAccountWithThirdParty( public record FormLoginRequest(String loginId, String password, boolean register, String source, String authId) { } + /** + * This endpoint is to get IDP configuration + * @param issuerUri String + * @param source String + * @param sourceName String + * @param clientId String + * @param clientSecret String + * @return Oauth2GenericAuthConfig + */ + @GetMapping("/providers") + public Mono> addOAuthProvider(@RequestParam String issuerUri, + @RequestParam String source, + @RequestParam String sourceName, + @RequestParam String clientId, + @RequestParam String clientSecret); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/GenericOAuthProviderSource.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/GenericOAuthProviderSource.java new file mode 100644 index 000000000..2963a5ea7 --- /dev/null +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/GenericOAuthProviderSource.java @@ -0,0 +1,31 @@ +package org.lowcoder.api.authentication.request.oauth2; + +import org.lowcoder.sdk.auth.Oauth2GenericAuthConfig; + +/** + * This class is the implementation of Oauth2Source and uses an instance of GenericOAuthProviderConfig + * to return the appropriate URLs + */ +public class GenericOAuthProviderSource implements Oauth2Source { + + private final Oauth2GenericAuthConfig config; + + public GenericOAuthProviderSource(Oauth2GenericAuthConfig config) { + this.config = config; + } + + @Override + public String accessToken() { + return config.getTokenEndpoint(); + } + + @Override + public String userInfo() { + return config.getUserInfoEndpoint(); + } + + @Override + public String refresh() { + return config.getTokenEndpoint(); + } +} \ No newline at end of file diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2AuthRequestFactory.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2AuthRequestFactory.java index c8fdae9b2..5444d203f 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2AuthRequestFactory.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2AuthRequestFactory.java @@ -4,11 +4,8 @@ import org.lowcoder.api.authentication.request.AuthRequest; import org.lowcoder.api.authentication.request.AuthRequestFactory; -import org.lowcoder.api.authentication.request.oauth2.request.AbstractOauth2Request; -import org.lowcoder.api.authentication.request.oauth2.request.GithubRequest; -import org.lowcoder.api.authentication.request.oauth2.request.GoogleRequest; -import org.lowcoder.api.authentication.request.oauth2.request.KeycloakRequest; -import org.lowcoder.api.authentication.request.oauth2.request.OryRequest; +import org.lowcoder.api.authentication.request.oauth2.request.*; +import org.lowcoder.sdk.auth.Oauth2GenericAuthConfig; import org.lowcoder.sdk.auth.Oauth2KeycloakAuthConfig; import org.lowcoder.sdk.auth.Oauth2OryAuthConfig; import org.lowcoder.sdk.auth.Oauth2SimpleAuthConfig; @@ -32,6 +29,7 @@ private AbstractOauth2Request buildRequest(OAu case GOOGLE -> new GoogleRequest((Oauth2SimpleAuthConfig) context.getAuthConfig()); case ORY -> new OryRequest((Oauth2OryAuthConfig) context.getAuthConfig()); case KEYCLOAK -> new KeycloakRequest((Oauth2KeycloakAuthConfig)context.getAuthConfig()); + case GENERIC -> new GenericAuthRequest((Oauth2GenericAuthConfig) context.getAuthConfig()); default -> throw new UnsupportedOperationException(context.getAuthConfig().getAuthType()); }; } @@ -42,6 +40,7 @@ public Set supportedAuthTypes() { GITHUB, GOOGLE, ORY, - KEYCLOAK); + KEYCLOAK, + GENERIC); } } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/request/GenericAuthRequest.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/request/GenericAuthRequest.java new file mode 100644 index 000000000..4512141a0 --- /dev/null +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/request/GenericAuthRequest.java @@ -0,0 +1,91 @@ +package org.lowcoder.api.authentication.request.oauth2.request; + +import org.lowcoder.api.authentication.request.AuthException; +import org.lowcoder.api.authentication.request.oauth2.GenericOAuthProviderSource; +import org.lowcoder.api.authentication.request.oauth2.OAuth2RequestContext; +import org.lowcoder.domain.user.model.AuthToken; +import org.lowcoder.domain.user.model.AuthUser; +import org.lowcoder.sdk.auth.Oauth2GenericAuthConfig; +import org.lowcoder.sdk.auth.Oauth2KeycloakAuthConfig; +import org.lowcoder.sdk.util.JsonUtils; +import org.lowcoder.sdk.webclient.WebClientBuildHelper; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.BodyInserters; +import reactor.core.publisher.Mono; + +import java.util.Map; + +import static org.lowcoder.api.authentication.util.AuthenticationUtils.mapToAuthToken; +import static org.lowcoder.api.authentication.util.AuthenticationUtils.mapToAuthUser; + +/** + * This class is for Generic Auth Request + */ +public class GenericAuthRequest extends AbstractOauth2Request{ + + public GenericAuthRequest(Oauth2GenericAuthConfig context) { + super(context, new GenericOAuthProviderSource(context)); + } + + @Override + protected Mono getAuthToken(OAuth2RequestContext context) { + return WebClientBuildHelper.builder() + .systemProxy() + .build() + .post() + .uri(config.getTokenEndpoint()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body(BodyInserters.fromFormData("code", context.getCode()) + .with("client_id", config.getClientId()) + .with("client_secret", config.getClientSecret()) + .with("grant_type", "authorization_code") + .with("redirect_uri", context.getRedirectUrl())) + .retrieve() + .bodyToMono(Map.class) + .flatMap(map -> { + if (map.containsKey("error") || map.containsKey("error_description")) { + return Mono.error(new AuthException(JsonUtils.toJson(map))); + } + return Mono.just(mapToAuthToken(map)); + }); + } + + @Override + protected Mono refreshAuthToken(String refreshToken) { + return WebClientBuildHelper.builder() + .systemProxy() + .build() + .post() + .uri(config.getTokenEndpoint()) + .body(BodyInserters.fromFormData("grant_type", "refresh_token") + .with("refresh_token", refreshToken) + .with("client_id", config.getClientId()) + .with("client_secret", config.getClientSecret())) + .retrieve() + .bodyToMono(Map.class) + .flatMap(map -> { + if (map.containsKey("error") || map.containsKey("error_description")) { + return Mono.error(new AuthException(JsonUtils.toJson(map))); + } + return Mono.just(mapToAuthToken(map)); + }); + } + + @Override + protected Mono getAuthUser(AuthToken authToken) { + return WebClientBuildHelper.builder() + .systemProxy() + .build() + .get() + .uri(config.getUserInfoEndpoint()) + .headers(headers -> headers.setBearerAuth(authToken.getAccessToken())) + .retrieve() + .bodyToMono(Map.class) + .flatMap(map -> { + if (map.containsKey("error") || map.containsKey("error_description")) { + return Mono.error(new AuthException(JsonUtils.toJson(map))); + } + return Mono.just(mapToAuthUser(map)); + }); + } +} diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java index cdf8cea97..f0872c3f4 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java @@ -6,6 +6,7 @@ import org.lowcoder.domain.authentication.FindAuthConfig; import org.lowcoder.domain.user.model.APIKey; import org.lowcoder.domain.user.model.AuthUser; +import org.lowcoder.sdk.auth.Oauth2GenericAuthConfig; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -29,4 +30,19 @@ public interface AuthenticationApiService { Mono deleteAPIKey(String authId); Flux findAPIKeys(); + + /** + * This method is to fetch and parse the OpenID configuration from the issuer URI. + * @param issuerUri String + * @param source String + * @param sourceName String + * @param clientId String + * @param clientSecret String + * @return Oauth2GenericAuthConfig + */ + Mono fetchAndParseConfiguration(String issuerUri, + String source, + String sourceName, + String clientId, + String clientSecret); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java index 110831c98..668e96c55 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java @@ -31,10 +31,13 @@ import org.lowcoder.domain.user.model.*; import org.lowcoder.domain.user.service.UserService; import org.lowcoder.sdk.auth.AbstractAuthConfig; +import org.lowcoder.sdk.auth.Oauth2GenericAuthConfig; +import org.lowcoder.sdk.auth.constants.AuthTypeConstants; import org.lowcoder.sdk.config.AuthProperties; import org.lowcoder.sdk.exception.BizError; import org.lowcoder.sdk.exception.BizException; import org.lowcoder.sdk.util.CookieHelper; +import org.lowcoder.sdk.webclient.WebClientBuildHelper; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.web.server.ServerWebExchange; @@ -330,6 +333,55 @@ public Flux findAPIKeys() { ); } + /** + * This method is to fetch and parse the OpenID configuration from the issuer URI. + * @param issuerUri String + * @param source String + * @param sourceName String + * @param clientId String + * @param clientSecret String + * @return Oauth2GenericAuthConfig + */ + @Override + public Mono fetchAndParseConfiguration(String issuerUri, + String source, + String sourceName, + String clientId, + String clientSecret) { + String wellKnownUri = issuerUri + "/.well-known/openid-configuration"; + return WebClientBuildHelper.builder() + .systemProxy() + .build() + .get() + .uri(wellKnownUri) + .retrieve() + .bodyToMono(Map.class) + .map(map -> mapToConfig(map, source, sourceName, clientId, clientSecret)); + } + + /** + * This method is to map to config for Generic Auth Provider + * @param map Object that comes from /.well-known endpoint for IDP Configuration + * @return Oauth2GenericAuthConfig + */ + private Oauth2GenericAuthConfig mapToConfig(Map map, + String source, + String sourceName, + String clientId, + String clientSecret) { + return Oauth2GenericAuthConfig.builder() + .authType(AuthTypeConstants.GENERIC) + .source(source) + .sourceName(sourceName) + .clientId(clientId) + .clientSecret(clientSecret) + .issuerUri((String) map.get("issuer")) + .authorizationEndpoint((String) map.get("authorization_endpoint")) + .tokenEndpoint((String) map.get("token_endpoint")) + .userInfoEndpoint((String) map.get("userinfo_endpoint")) + .build(); + } + private Mono removeTokensByAuthId(String authId) { return sessionUserService.getVisitorOrgMemberCache() diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java index be3854df1..7f8398395 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java @@ -10,11 +10,7 @@ import org.apache.commons.collections4.MapUtils; import org.lowcoder.api.authentication.dto.AuthConfigRequest; -import org.lowcoder.sdk.auth.AbstractAuthConfig; -import org.lowcoder.sdk.auth.EmailAuthConfig; -import org.lowcoder.sdk.auth.Oauth2KeycloakAuthConfig; -import org.lowcoder.sdk.auth.Oauth2OryAuthConfig; -import org.lowcoder.sdk.auth.Oauth2SimpleAuthConfig; +import org.lowcoder.sdk.auth.*; import org.lowcoder.sdk.auth.constants.AuthTypeConstants; import org.springframework.stereotype.Component; @@ -29,6 +25,7 @@ public AbstractAuthConfig build(AuthConfigRequest authConfigRequest, boolean ena case AuthTypeConstants.GOOGLE -> buildOauth2SimpleAuthConfig(GOOGLE, GOOGLE_NAME, authConfigRequest, enable); case AuthTypeConstants.ORY -> buildOauth2OryAuthConfig(authConfigRequest, enable); case AuthTypeConstants.KEYCLOAK -> buildOauth2KeycloakAuthConfig(authConfigRequest, enable); + case AuthTypeConstants.GENERIC -> buildOauth2GenericAuthConfig(authConfigRequest, enable); default -> throw new UnsupportedOperationException(authConfigRequest.getAuthType()); }; } @@ -40,7 +37,8 @@ public Set supportAuthTypes() { AuthTypeConstants.GITHUB, AuthTypeConstants.GOOGLE, AuthTypeConstants.ORY, - AuthTypeConstants.KEYCLOAK + AuthTypeConstants.KEYCLOAK, + AuthTypeConstants.GENERIC ); } @@ -93,5 +91,28 @@ private Oauth2SimpleAuthConfig buildOauth2KeycloakAuthConfig(AuthConfigRequest a .authType(authConfigRequest.getAuthType()) .build(); } - + + /** + * This method is to build Oauth2GenericAuth config + * @param authConfigRequest AuthConfigRequest + * @param enable boolean + * @return Oauth2SimpleAuthConfig + */ + private Oauth2SimpleAuthConfig buildOauth2GenericAuthConfig(AuthConfigRequest authConfigRequest, boolean enable) { + return Oauth2GenericAuthConfig.builder() + .id(authConfigRequest.getId()) + .enable(enable) + .enableRegister(authConfigRequest.isEnableRegister()) + .source(AuthTypeConstants.GENERIC) + .sourceName(org.lowcoder.sdk.constants.AuthSourceConstants.KEYCLOAK_NAME) + .clientId(requireNonNull(authConfigRequest.getClientId(), "clientId can not be null.")) + .clientSecret(authConfigRequest.getClientSecret()) + .issuerUri(authConfigRequest.getString("issuer")) + .authorizationEndpoint(authConfigRequest.getString("authorization_endpoint")) + .tokenEndpoint(authConfigRequest.getString("token_endpoint")) + .userInfoEndpoint(authConfigRequest.getString("userinfo_endpoint")) + .authType(authConfigRequest.getAuthType()) + .build(); + + } } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/util/AuthenticationUtils.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/util/AuthenticationUtils.java index 6ef443ac9..e828cb588 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/util/AuthenticationUtils.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/util/AuthenticationUtils.java @@ -4,7 +4,11 @@ import static reactor.core.scheduler.Schedulers.newBoundedElastic; import java.util.Collection; +import java.util.Map; +import org.apache.commons.collections4.MapUtils; +import org.lowcoder.domain.user.model.AuthToken; +import org.lowcoder.domain.user.model.AuthUser; import org.lowcoder.domain.user.model.User; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -57,4 +61,29 @@ public String getName() { }; } + /** + * Utility method to map from Map to AuthToken + * @param map Object + * @return AuthToken + */ + public static AuthToken mapToAuthToken(Map map) { + return AuthToken.builder() + .accessToken(MapUtils.getString(map, "access_token")) + .expireIn(MapUtils.getIntValue(map, "expires_in")) + .refreshToken(MapUtils.getString(map, "refresh_token")) + .build(); + } + + /** + * Utility method to map from Map to AuthUser + * @param map Object + * @return AuthUser + */ + public static AuthUser mapToAuthUser(Map map) { + return AuthUser.builder() + .uid(MapUtils.getString(map, "sub")) + .username(MapUtils.getString(map, "email")) + .rawUserInfo(map) + .build(); + } } From e2506d6bc2e8861118b1f169d9b1a3c4a6a821fb Mon Sep 17 00:00:00 2001 From: th37rose Date: Fri, 3 May 2024 16:55:43 +0000 Subject: [PATCH 02/12] Implemented the generic Auth feature without additional .well_known endpoint. --- .../sdk/auth/Oauth2SimpleAuthConfig.java | 2 +- .../AuthenticationController.java | 20 -------- .../AuthenticationEndpoints.java | 16 ------ .../authentication/dto/AuthConfigRequest.java | 25 ++++++++++ .../oauth2/request/GenericAuthRequest.java | 1 - .../service/AuthenticationApiService.java | 16 ------ .../service/AuthenticationApiServiceImpl.java | 50 ------------------- .../factory/AuthConfigFactoryImpl.java | 16 +++--- 8 files changed, 34 insertions(+), 112 deletions(-) diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java index 81d17d915..c93b7eb6b 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java @@ -38,7 +38,7 @@ public String getAuthorizeUrl() { case AuthTypeConstants.GITHUB -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.GITHUB_AUTHORIZE_URL); case AuthTypeConstants.ORY -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.ORY_AUTHORIZE_URL); case AuthTypeConstants.KEYCLOAK -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.KEYCLOAK_AUTHORIZE_URL); - case AuthTypeConstants.GENERIC -> replaceAuthUrlClientIdPlaceholder(((Oauth2GenericAuthConfig)this).getAuthorizationEndpoint()); + case AuthTypeConstants.GENERIC -> ((Oauth2GenericAuthConfig)this).getAuthorizationEndpoint(); default -> null; }; } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java index 89c666d9e..b66fe752a 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java @@ -130,24 +130,4 @@ public Mono>> getAllAPIKeys() { .collectList() .map(ResponseView::success); } - - /** - * This endpoint is to get IDP configuration - * @param issuerUri String - * @param source String - * @param sourceName String - * @param clientId String - * @param clientSecret String - * @return Oauth2GenericAuthConfig - */ - @Override - public Mono> addOAuthProvider(String issuerUri, - String source, - String sourceName, - String clientId, - String clientSecret) { - return authenticationApiService.fetchAndParseConfiguration(issuerUri, source, sourceName, clientId, clientSecret) - .map(ResponseView::success); - } - } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationEndpoints.java index 1668fbfe4..3a00320cd 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationEndpoints.java @@ -162,20 +162,4 @@ public Mono> linkAccountWithThirdParty( */ public record FormLoginRequest(String loginId, String password, boolean register, String source, String authId) { } - - /** - * This endpoint is to get IDP configuration - * @param issuerUri String - * @param source String - * @param sourceName String - * @param clientId String - * @param clientSecret String - * @return Oauth2GenericAuthConfig - */ - @GetMapping("/providers") - public Mono> addOAuthProvider(@RequestParam String issuerUri, - @RequestParam String source, - @RequestParam String sourceName, - @RequestParam String clientId, - @RequestParam String clientSecret); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/dto/AuthConfigRequest.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/dto/AuthConfigRequest.java index 3b8cb98fa..7c3c3bf79 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/dto/AuthConfigRequest.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/dto/AuthConfigRequest.java @@ -1,6 +1,7 @@ package org.lowcoder.api.authentication.dto; import jakarta.annotation.Nullable; +import jakarta.validation.constraints.Null; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -27,6 +28,30 @@ public boolean isEnableRegister() { return MapUtils.getBoolean(this, "enableRegister", true); } + /** + * Additional configs for generic + * config will be updated instead of creating a new one. + */ + @Nullable + public String getIssuerUri() { + return getString("issuer"); + } + + @Nullable + public String getAuthorizationEndpoint() { + return getString("authorizationEndpoint"); + } + + @Nullable + public String getTokenEndpoint() { + return getString("tokenEndpoint"); + } + + @Nullable + public String getUserInfoEndpoint() { + return getString("userInfoEndpoint"); + } + @Nullable public String getInstanceId() { return getString("instanceId"); diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/request/GenericAuthRequest.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/request/GenericAuthRequest.java index 4512141a0..bdf7305c4 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/request/GenericAuthRequest.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/request/GenericAuthRequest.java @@ -6,7 +6,6 @@ import org.lowcoder.domain.user.model.AuthToken; import org.lowcoder.domain.user.model.AuthUser; import org.lowcoder.sdk.auth.Oauth2GenericAuthConfig; -import org.lowcoder.sdk.auth.Oauth2KeycloakAuthConfig; import org.lowcoder.sdk.util.JsonUtils; import org.lowcoder.sdk.webclient.WebClientBuildHelper; import org.springframework.http.MediaType; diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java index f0872c3f4..cdf8cea97 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java @@ -6,7 +6,6 @@ import org.lowcoder.domain.authentication.FindAuthConfig; import org.lowcoder.domain.user.model.APIKey; import org.lowcoder.domain.user.model.AuthUser; -import org.lowcoder.sdk.auth.Oauth2GenericAuthConfig; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -30,19 +29,4 @@ public interface AuthenticationApiService { Mono deleteAPIKey(String authId); Flux findAPIKeys(); - - /** - * This method is to fetch and parse the OpenID configuration from the issuer URI. - * @param issuerUri String - * @param source String - * @param sourceName String - * @param clientId String - * @param clientSecret String - * @return Oauth2GenericAuthConfig - */ - Mono fetchAndParseConfiguration(String issuerUri, - String source, - String sourceName, - String clientId, - String clientSecret); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java index 668e96c55..3072c133c 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java @@ -333,56 +333,6 @@ public Flux findAPIKeys() { ); } - /** - * This method is to fetch and parse the OpenID configuration from the issuer URI. - * @param issuerUri String - * @param source String - * @param sourceName String - * @param clientId String - * @param clientSecret String - * @return Oauth2GenericAuthConfig - */ - @Override - public Mono fetchAndParseConfiguration(String issuerUri, - String source, - String sourceName, - String clientId, - String clientSecret) { - String wellKnownUri = issuerUri + "/.well-known/openid-configuration"; - return WebClientBuildHelper.builder() - .systemProxy() - .build() - .get() - .uri(wellKnownUri) - .retrieve() - .bodyToMono(Map.class) - .map(map -> mapToConfig(map, source, sourceName, clientId, clientSecret)); - } - - /** - * This method is to map to config for Generic Auth Provider - * @param map Object that comes from /.well-known endpoint for IDP Configuration - * @return Oauth2GenericAuthConfig - */ - private Oauth2GenericAuthConfig mapToConfig(Map map, - String source, - String sourceName, - String clientId, - String clientSecret) { - return Oauth2GenericAuthConfig.builder() - .authType(AuthTypeConstants.GENERIC) - .source(source) - .sourceName(sourceName) - .clientId(clientId) - .clientSecret(clientSecret) - .issuerUri((String) map.get("issuer")) - .authorizationEndpoint((String) map.get("authorization_endpoint")) - .tokenEndpoint((String) map.get("token_endpoint")) - .userInfoEndpoint((String) map.get("userinfo_endpoint")) - .build(); - } - - private Mono removeTokensByAuthId(String authId) { return sessionUserService.getVisitorOrgMemberCache() .flatMapMany(orgMember -> orgMemberService.getOrganizationMembers(orgMember.getOrgId())) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java index 7f8398395..f3425cda7 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java @@ -19,6 +19,7 @@ public class AuthConfigFactoryImpl implements AuthConfigFactory { @Override public AbstractAuthConfig build(AuthConfigRequest authConfigRequest, boolean enable) { + buildOauth2GenericAuthConfig(authConfigRequest, enable); return switch (authConfigRequest.getAuthType()) { case AuthTypeConstants.FORM -> buildEmailAuthConfig(authConfigRequest, enable); case AuthTypeConstants.GITHUB -> buildOauth2SimpleAuthConfig(GITHUB, GITHUB_NAME, authConfigRequest, enable); @@ -103,16 +104,15 @@ private Oauth2SimpleAuthConfig buildOauth2GenericAuthConfig(AuthConfigRequest au .id(authConfigRequest.getId()) .enable(enable) .enableRegister(authConfigRequest.isEnableRegister()) - .source(AuthTypeConstants.GENERIC) - .sourceName(org.lowcoder.sdk.constants.AuthSourceConstants.KEYCLOAK_NAME) + .source(authConfigRequest.getSource(AuthTypeConstants.GENERIC)) + .sourceName(authConfigRequest.getSourceName(AuthTypeConstants.GENERIC)) .clientId(requireNonNull(authConfigRequest.getClientId(), "clientId can not be null.")) .clientSecret(authConfigRequest.getClientSecret()) - .issuerUri(authConfigRequest.getString("issuer")) - .authorizationEndpoint(authConfigRequest.getString("authorization_endpoint")) - .tokenEndpoint(authConfigRequest.getString("token_endpoint")) - .userInfoEndpoint(authConfigRequest.getString("userinfo_endpoint")) - .authType(authConfigRequest.getAuthType()) + .issuerUri(authConfigRequest.getIssuerUri()) + .authorizationEndpoint(authConfigRequest.getAuthorizationEndpoint()) + .tokenEndpoint(authConfigRequest.getTokenEndpoint()) + .userInfoEndpoint(authConfigRequest.getUserInfoEndpoint()) + .authType(AuthTypeConstants.GENERIC) .build(); - } } From c4281db9c262788f52cb3b92150ae685fd338650 Mon Sep 17 00:00:00 2001 From: Ludo Mikula Date: Fri, 10 May 2024 09:33:44 +0200 Subject: [PATCH 03/12] fix: fixed viewing of apps of other users --- .../repository/ApplicationRepository.java | 2 ++ .../service/ApplicationService.java | 4 ++-- .../service/ApplicationServiceImpl.java | 21 ++++++++++++++----- .../service/ApplicationPermissionHandler.java | 10 ++++----- .../service/DatasourcePermissionHandler.java | 4 ++-- .../service/ResourcePermissionHandler.java | 8 +++---- 6 files changed, 31 insertions(+), 18 deletions(-) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java index 66a0f41e0..7c1ad43df 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java @@ -32,6 +32,8 @@ public interface ApplicationRepository extends ReactiveMongoRepository findByIdIn(Collection ids); + Flux findByCreatedByAndIdIn(String userId, Collection ids); + /** * Filter public applications from list of supplied IDs */ diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java index 3bdcbac9f..f89a99172 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java @@ -52,7 +52,7 @@ public interface ApplicationService { @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") - Mono> getFilteredPublicApplicationIds(ApplicationRequestType requestType, Collection applicationIds, boolean isAnonymous, Boolean isPrivateMarketplace); + Mono> getFilteredPublicApplicationIds(ApplicationRequestType requestType, Collection applicationIds, String userId, Boolean isPrivateMarketplace); @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") @@ -60,7 +60,7 @@ public interface ApplicationService { @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") - Mono> getPrivateApplicationIds(Collection applicationIds); + Mono> getPrivateApplicationIds(Collection applicationIds, String userId); @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationServiceImpl.java index a7224e946..786536fd1 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationServiceImpl.java @@ -7,12 +7,17 @@ import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; import org.lowcoder.domain.application.model.Application; import org.lowcoder.domain.application.model.ApplicationRequestType; import org.lowcoder.domain.application.model.ApplicationStatus; import org.lowcoder.domain.application.repository.ApplicationRepository; +import org.lowcoder.domain.organization.repository.OrganizationRepository; +import org.lowcoder.domain.organization.service.OrgMemberService; import org.lowcoder.domain.permission.model.ResourceRole; import org.lowcoder.domain.permission.service.ResourcePermissionService; +import org.lowcoder.domain.user.repository.UserRepository; +import org.lowcoder.domain.user.service.UserService; import org.lowcoder.infra.annotation.NonEmptyMono; import org.lowcoder.infra.mongo.MongoUpsertHelper; import org.lowcoder.sdk.constants.FieldName; @@ -37,6 +42,7 @@ public class ApplicationServiceImpl implements ApplicationService { private final MongoUpsertHelper mongoUpsertHelper; private final ResourcePermissionService resourcePermissionService; private final ApplicationRepository repository; + private final UserRepository userRepository; @Override public Mono findById(String id) { @@ -219,8 +225,8 @@ public Mono setApplicationAsAgencyProfile(String applicationId, boolean @Override @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") - public Mono> getFilteredPublicApplicationIds(ApplicationRequestType requestType, Collection applicationIds, boolean isAnonymous, Boolean isPrivateMarketplace) { - + public Mono> getFilteredPublicApplicationIds(ApplicationRequestType requestType, Collection applicationIds, String userId, Boolean isPrivateMarketplace) { + boolean isAnonymous = StringUtils.isBlank(userId); switch(requestType) { case PUBLIC_TO_ALL: @@ -230,7 +236,7 @@ public Mono> getFilteredPublicApplicationIds(ApplicationRequestType } else { - return getPrivateApplicationIds(applicationIds); + return getPrivateApplicationIds(applicationIds, userId); } case PUBLIC_TO_MARKETPLACE: return getPublicMarketplaceApplicationIds(applicationIds, isAnonymous, isPrivateMarketplace); @@ -262,11 +268,16 @@ public Mono> getPublicApplicationIds(Collection applicationI @Override @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") - public Mono> getPrivateApplicationIds(Collection applicationIds) { + public Mono> getPrivateApplicationIds(Collection applicationIds, String userId) { + // TODO: in 2.4.0 we need to check whether the app was published or not - return repository.findByIdIn(applicationIds) + return repository.findByCreatedByAndIdIn(userId, applicationIds) .map(HasIdAndAuditing::getId) .collect(Collectors.toSet()); + +// return repository.findByIdIn(applicationIds) +// .map(HasIdAndAuditing::getId) +// .collect(Collectors.toSet()); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ApplicationPermissionHandler.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ApplicationPermissionHandler.java index 7c92cc3d4..011c18410 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ApplicationPermissionHandler.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ApplicationPermissionHandler.java @@ -53,10 +53,10 @@ protected Mono>> getAnonymousUserPermission // This is for PTM apps that are public but only available to logged-in users @Override protected Mono>> getNonAnonymousUserPublicResourcePermissions - (Collection resourceIds, ResourceAction resourceAction) { + (Collection resourceIds, ResourceAction resourceAction, String userId) { Set applicationIds = newHashSet(resourceIds); - return Mono.zip(applicationService.getPrivateApplicationIds(applicationIds), + return Mono.zip(applicationService.getPrivateApplicationIds(applicationIds, userId), templateSolutionService.getTemplateApplicationIds(applicationIds)) .map(tuple -> { Set publicAppIds = tuple.getT1(); @@ -75,7 +75,7 @@ protected Mono>> getAnonymousUserApplicatio } Set applicationIds = newHashSet(resourceIds); - return Mono.zip(applicationService.getFilteredPublicApplicationIds(requestType, applicationIds, Boolean.TRUE, config.getMarketplace().isPrivateMode()) + return Mono.zip(applicationService.getFilteredPublicApplicationIds(requestType, applicationIds, null, config.getMarketplace().isPrivateMode()) .defaultIfEmpty(new HashSet<>()), templateSolutionService.getTemplateApplicationIds(applicationIds) .defaultIfEmpty(new HashSet<>()) @@ -88,9 +88,9 @@ protected Mono>> getAnonymousUserApplicatio @Override protected Mono>> getNonAnonymousUserApplicationPublicResourcePermissions( - Collection resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType) { + Collection resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType, String userId) { Set applicationIds = newHashSet(resourceIds); - return Mono.zip(applicationService.getFilteredPublicApplicationIds(requestType, applicationIds, Boolean.FALSE, config.getMarketplace().isPrivateMode()), + return Mono.zip(applicationService.getFilteredPublicApplicationIds(requestType, applicationIds, userId, config.getMarketplace().isPrivateMode()), templateSolutionService.getTemplateApplicationIds(applicationIds)) .map(tuple -> { Set publicAppIds = tuple.getT1(); diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/DatasourcePermissionHandler.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/DatasourcePermissionHandler.java index 200a9b6a8..24b3475d5 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/DatasourcePermissionHandler.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/DatasourcePermissionHandler.java @@ -36,7 +36,7 @@ protected Mono>> getAnonymousUserPermission } @Override - protected Mono>> getNonAnonymousUserPublicResourcePermissions(Collection resourceIds, ResourceAction resourceAction) { + protected Mono>> getNonAnonymousUserPublicResourcePermissions(Collection resourceIds, ResourceAction resourceAction, String userId) { return Mono.just(Collections.emptyMap()); } @@ -48,7 +48,7 @@ protected Mono>> getAnonymousUserApplicatio @Override protected Mono>> getNonAnonymousUserApplicationPublicResourcePermissions( - Collection resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType) { + Collection resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType, String userId) { return Mono.just(Collections.emptyMap()); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionHandler.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionHandler.java index 115d74eb0..2ec65a080 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionHandler.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionHandler.java @@ -88,7 +88,7 @@ public Mono checkUserPermissionStatusOnResource( return publicResourcePermissionMono; } - Mono nonAnonymousPublicResourcePermissionMono = getNonAnonymousUserPublicResourcePermissions(singletonList(resourceId), resourceAction) + Mono nonAnonymousPublicResourcePermissionMono = getNonAnonymousUserPublicResourcePermissions(singletonList(resourceId), resourceAction, userId) .map(it -> it.getOrDefault(resourceId, emptyList())) .map(it -> { if (!it.isEmpty()) { @@ -141,13 +141,13 @@ protected abstract Mono>> getAnonymousUserP ResourceAction resourceAction); protected abstract Mono>> getNonAnonymousUserPublicResourcePermissions - (Collection resourceIds, ResourceAction resourceAction); + (Collection resourceIds, ResourceAction resourceAction, String userId); protected abstract Mono>> getAnonymousUserApplicationPermissions(Collection resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType); protected abstract Mono>> getNonAnonymousUserApplicationPublicResourcePermissions - (Collection resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType); + (Collection resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType, String userId); private Mono>> getAllMatchingPermissions0(String userId, String orgId, ResourceType resourceType, @@ -229,7 +229,7 @@ public Mono checkUserPermissionStatusOnApplicati return publicResourcePermissionMono; } - Mono nonAnonymousPublicResourcePermissionMono = getNonAnonymousUserApplicationPublicResourcePermissions(singletonList(resourceId), resourceAction, requestType) + Mono nonAnonymousPublicResourcePermissionMono = getNonAnonymousUserApplicationPublicResourcePermissions(singletonList(resourceId), resourceAction, requestType, userId) .map(it -> it.getOrDefault(resourceId, emptyList())) .map(it -> { if (!it.isEmpty()) { From 3fa015f7ec9a22a37763771598e3f500fb769dda Mon Sep 17 00:00:00 2001 From: th37rose Date: Thu, 2 May 2024 07:33:13 +0000 Subject: [PATCH 04/12] Implemented the generic Auth feature. --- .../sdk/auth/Oauth2SimpleAuthConfig.java | 2 +- .../AuthenticationController.java | 20 ++++++++ .../service/AuthenticationApiService.java | 16 ++++++ .../service/AuthenticationApiServiceImpl.java | 50 +++++++++++++++++++ .../factory/AuthConfigFactoryImpl.java | 1 - 5 files changed, 87 insertions(+), 2 deletions(-) diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java index c93b7eb6b..81d17d915 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java @@ -38,7 +38,7 @@ public String getAuthorizeUrl() { case AuthTypeConstants.GITHUB -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.GITHUB_AUTHORIZE_URL); case AuthTypeConstants.ORY -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.ORY_AUTHORIZE_URL); case AuthTypeConstants.KEYCLOAK -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.KEYCLOAK_AUTHORIZE_URL); - case AuthTypeConstants.GENERIC -> ((Oauth2GenericAuthConfig)this).getAuthorizationEndpoint(); + case AuthTypeConstants.GENERIC -> replaceAuthUrlClientIdPlaceholder(((Oauth2GenericAuthConfig)this).getAuthorizationEndpoint()); default -> null; }; } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java index b66fe752a..89c666d9e 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java @@ -130,4 +130,24 @@ public Mono>> getAllAPIKeys() { .collectList() .map(ResponseView::success); } + + /** + * This endpoint is to get IDP configuration + * @param issuerUri String + * @param source String + * @param sourceName String + * @param clientId String + * @param clientSecret String + * @return Oauth2GenericAuthConfig + */ + @Override + public Mono> addOAuthProvider(String issuerUri, + String source, + String sourceName, + String clientId, + String clientSecret) { + return authenticationApiService.fetchAndParseConfiguration(issuerUri, source, sourceName, clientId, clientSecret) + .map(ResponseView::success); + } + } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java index cdf8cea97..f0872c3f4 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java @@ -6,6 +6,7 @@ import org.lowcoder.domain.authentication.FindAuthConfig; import org.lowcoder.domain.user.model.APIKey; import org.lowcoder.domain.user.model.AuthUser; +import org.lowcoder.sdk.auth.Oauth2GenericAuthConfig; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -29,4 +30,19 @@ public interface AuthenticationApiService { Mono deleteAPIKey(String authId); Flux findAPIKeys(); + + /** + * This method is to fetch and parse the OpenID configuration from the issuer URI. + * @param issuerUri String + * @param source String + * @param sourceName String + * @param clientId String + * @param clientSecret String + * @return Oauth2GenericAuthConfig + */ + Mono fetchAndParseConfiguration(String issuerUri, + String source, + String sourceName, + String clientId, + String clientSecret); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java index 3072c133c..668e96c55 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java @@ -333,6 +333,56 @@ public Flux findAPIKeys() { ); } + /** + * This method is to fetch and parse the OpenID configuration from the issuer URI. + * @param issuerUri String + * @param source String + * @param sourceName String + * @param clientId String + * @param clientSecret String + * @return Oauth2GenericAuthConfig + */ + @Override + public Mono fetchAndParseConfiguration(String issuerUri, + String source, + String sourceName, + String clientId, + String clientSecret) { + String wellKnownUri = issuerUri + "/.well-known/openid-configuration"; + return WebClientBuildHelper.builder() + .systemProxy() + .build() + .get() + .uri(wellKnownUri) + .retrieve() + .bodyToMono(Map.class) + .map(map -> mapToConfig(map, source, sourceName, clientId, clientSecret)); + } + + /** + * This method is to map to config for Generic Auth Provider + * @param map Object that comes from /.well-known endpoint for IDP Configuration + * @return Oauth2GenericAuthConfig + */ + private Oauth2GenericAuthConfig mapToConfig(Map map, + String source, + String sourceName, + String clientId, + String clientSecret) { + return Oauth2GenericAuthConfig.builder() + .authType(AuthTypeConstants.GENERIC) + .source(source) + .sourceName(sourceName) + .clientId(clientId) + .clientSecret(clientSecret) + .issuerUri((String) map.get("issuer")) + .authorizationEndpoint((String) map.get("authorization_endpoint")) + .tokenEndpoint((String) map.get("token_endpoint")) + .userInfoEndpoint((String) map.get("userinfo_endpoint")) + .build(); + } + + private Mono removeTokensByAuthId(String authId) { return sessionUserService.getVisitorOrgMemberCache() .flatMapMany(orgMember -> orgMemberService.getOrganizationMembers(orgMember.getOrgId())) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java index f3425cda7..f45440518 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java @@ -19,7 +19,6 @@ public class AuthConfigFactoryImpl implements AuthConfigFactory { @Override public AbstractAuthConfig build(AuthConfigRequest authConfigRequest, boolean enable) { - buildOauth2GenericAuthConfig(authConfigRequest, enable); return switch (authConfigRequest.getAuthType()) { case AuthTypeConstants.FORM -> buildEmailAuthConfig(authConfigRequest, enable); case AuthTypeConstants.GITHUB -> buildOauth2SimpleAuthConfig(GITHUB, GITHUB_NAME, authConfigRequest, enable); From accc0d954f9fca3f1199a9b70ae8b53207097311 Mon Sep 17 00:00:00 2001 From: th37rose Date: Fri, 3 May 2024 16:55:43 +0000 Subject: [PATCH 05/12] Implemented the generic Auth feature without additional .well_known endpoint. --- .../sdk/auth/Oauth2SimpleAuthConfig.java | 2 +- .../AuthenticationController.java | 20 -------- .../service/AuthenticationApiService.java | 16 ------ .../service/AuthenticationApiServiceImpl.java | 50 ------------------- .../factory/AuthConfigFactoryImpl.java | 1 + 5 files changed, 2 insertions(+), 87 deletions(-) diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java index 81d17d915..c93b7eb6b 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java @@ -38,7 +38,7 @@ public String getAuthorizeUrl() { case AuthTypeConstants.GITHUB -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.GITHUB_AUTHORIZE_URL); case AuthTypeConstants.ORY -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.ORY_AUTHORIZE_URL); case AuthTypeConstants.KEYCLOAK -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.KEYCLOAK_AUTHORIZE_URL); - case AuthTypeConstants.GENERIC -> replaceAuthUrlClientIdPlaceholder(((Oauth2GenericAuthConfig)this).getAuthorizationEndpoint()); + case AuthTypeConstants.GENERIC -> ((Oauth2GenericAuthConfig)this).getAuthorizationEndpoint(); default -> null; }; } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java index 89c666d9e..b66fe752a 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java @@ -130,24 +130,4 @@ public Mono>> getAllAPIKeys() { .collectList() .map(ResponseView::success); } - - /** - * This endpoint is to get IDP configuration - * @param issuerUri String - * @param source String - * @param sourceName String - * @param clientId String - * @param clientSecret String - * @return Oauth2GenericAuthConfig - */ - @Override - public Mono> addOAuthProvider(String issuerUri, - String source, - String sourceName, - String clientId, - String clientSecret) { - return authenticationApiService.fetchAndParseConfiguration(issuerUri, source, sourceName, clientId, clientSecret) - .map(ResponseView::success); - } - } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java index f0872c3f4..cdf8cea97 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiService.java @@ -6,7 +6,6 @@ import org.lowcoder.domain.authentication.FindAuthConfig; import org.lowcoder.domain.user.model.APIKey; import org.lowcoder.domain.user.model.AuthUser; -import org.lowcoder.sdk.auth.Oauth2GenericAuthConfig; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -30,19 +29,4 @@ public interface AuthenticationApiService { Mono deleteAPIKey(String authId); Flux findAPIKeys(); - - /** - * This method is to fetch and parse the OpenID configuration from the issuer URI. - * @param issuerUri String - * @param source String - * @param sourceName String - * @param clientId String - * @param clientSecret String - * @return Oauth2GenericAuthConfig - */ - Mono fetchAndParseConfiguration(String issuerUri, - String source, - String sourceName, - String clientId, - String clientSecret); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java index 668e96c55..3072c133c 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java @@ -333,56 +333,6 @@ public Flux findAPIKeys() { ); } - /** - * This method is to fetch and parse the OpenID configuration from the issuer URI. - * @param issuerUri String - * @param source String - * @param sourceName String - * @param clientId String - * @param clientSecret String - * @return Oauth2GenericAuthConfig - */ - @Override - public Mono fetchAndParseConfiguration(String issuerUri, - String source, - String sourceName, - String clientId, - String clientSecret) { - String wellKnownUri = issuerUri + "/.well-known/openid-configuration"; - return WebClientBuildHelper.builder() - .systemProxy() - .build() - .get() - .uri(wellKnownUri) - .retrieve() - .bodyToMono(Map.class) - .map(map -> mapToConfig(map, source, sourceName, clientId, clientSecret)); - } - - /** - * This method is to map to config for Generic Auth Provider - * @param map Object that comes from /.well-known endpoint for IDP Configuration - * @return Oauth2GenericAuthConfig - */ - private Oauth2GenericAuthConfig mapToConfig(Map map, - String source, - String sourceName, - String clientId, - String clientSecret) { - return Oauth2GenericAuthConfig.builder() - .authType(AuthTypeConstants.GENERIC) - .source(source) - .sourceName(sourceName) - .clientId(clientId) - .clientSecret(clientSecret) - .issuerUri((String) map.get("issuer")) - .authorizationEndpoint((String) map.get("authorization_endpoint")) - .tokenEndpoint((String) map.get("token_endpoint")) - .userInfoEndpoint((String) map.get("userinfo_endpoint")) - .build(); - } - - private Mono removeTokensByAuthId(String authId) { return sessionUserService.getVisitorOrgMemberCache() .flatMapMany(orgMember -> orgMemberService.getOrganizationMembers(orgMember.getOrgId())) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java index f45440518..f3425cda7 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java @@ -19,6 +19,7 @@ public class AuthConfigFactoryImpl implements AuthConfigFactory { @Override public AbstractAuthConfig build(AuthConfigRequest authConfigRequest, boolean enable) { + buildOauth2GenericAuthConfig(authConfigRequest, enable); return switch (authConfigRequest.getAuthType()) { case AuthTypeConstants.FORM -> buildEmailAuthConfig(authConfigRequest, enable); case AuthTypeConstants.GITHUB -> buildOauth2SimpleAuthConfig(GITHUB, GITHUB_NAME, authConfigRequest, enable); From b1e593e699d4913eb6728a3cd0519827d8947182 Mon Sep 17 00:00:00 2001 From: th37rose Date: Mon, 6 May 2024 08:13:16 +0000 Subject: [PATCH 06/12] Added scope mapping for generic auth. --- .../org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java | 1 + .../lowcoder/api/authentication/dto/AuthConfigRequest.java | 7 ++++++- .../service/factory/AuthConfigFactoryImpl.java | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java index 1f8fcd604..c60314dda 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java @@ -15,4 +15,5 @@ public class Oauth2GenericAuthConfig extends Oauth2SimpleAuthConfig { private String authorizationEndpoint; private String tokenEndpoint; private String userInfoEndpoint; + private String scope; } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/dto/AuthConfigRequest.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/dto/AuthConfigRequest.java index 7c3c3bf79..683abab99 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/dto/AuthConfigRequest.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/dto/AuthConfigRequest.java @@ -34,7 +34,7 @@ public boolean isEnableRegister() { */ @Nullable public String getIssuerUri() { - return getString("issuer"); + return getString("issuerUri"); } @Nullable @@ -67,6 +67,11 @@ public String getClientSecret() { return getString("clientSecret"); } + @Nullable + public String getScope() { + return getString("scope"); + } + public String getSource(String defaultValue) { String source = getString("source"); if (StringUtils.isNotBlank(source)) { diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java index f3425cda7..a19172e7d 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java @@ -112,6 +112,7 @@ private Oauth2SimpleAuthConfig buildOauth2GenericAuthConfig(AuthConfigRequest au .authorizationEndpoint(authConfigRequest.getAuthorizationEndpoint()) .tokenEndpoint(authConfigRequest.getTokenEndpoint()) .userInfoEndpoint(authConfigRequest.getUserInfoEndpoint()) + .scope(authConfigRequest.getScope()) .authType(AuthTypeConstants.GENERIC) .build(); } From 91dc2bb70e41c999bcd4d67f762befaa14dcc24f Mon Sep 17 00:00:00 2001 From: th37rose Date: Wed, 8 May 2024 20:00:01 +0000 Subject: [PATCH 07/12] Set max age of cookie to 24h/1d --- .../src/main/java/org/lowcoder/sdk/config/CommonConfig.java | 4 ++-- .../java/org/lowcoder/api/home/SessionUserServiceImpl.java | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/config/CommonConfig.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/config/CommonConfig.java index b6fed12ee..bc49625c7 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/config/CommonConfig.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/config/CommonConfig.java @@ -141,8 +141,8 @@ public static class Workspace { @Data public static class Cookie { - - private long maxAgeInSeconds = Duration.ofDays(30).toSeconds(); + //Set cookie max age to 1 day + private long maxAgeInSeconds = Duration.ofDays(1).toSeconds(); } @Data diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/SessionUserServiceImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/SessionUserServiceImpl.java index 75b5bec8d..eb23baea0 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/SessionUserServiceImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/SessionUserServiceImpl.java @@ -118,10 +118,7 @@ public Mono extendValidity(String token) { private Duration getTokenExpireTime() { long maxAgeInSeconds = commonConfig.getCookie().getMaxAgeInSeconds(); - if (maxAgeInSeconds >= 0) { - return Duration.ofSeconds(maxAgeInSeconds).plus(Duration.ofDays(1)); - } - return Duration.ofDays(7); + return Duration.ofSeconds(maxAgeInSeconds); } @Override From 1eaca8a1941663622912205bf6b8a11881c2f6bd Mon Sep 17 00:00:00 2001 From: Ludo Mikula Date: Fri, 10 May 2024 13:37:37 +0200 Subject: [PATCH 08/12] chore: upgrade mongodb version to 7.0 --- deploy/docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/docker/Dockerfile b/deploy/docker/Dockerfile index 94ebcdcea..574e3334c 100644 --- a/deploy/docker/Dockerfile +++ b/deploy/docker/Dockerfile @@ -204,8 +204,8 @@ RUN mkdir -p /etc/apt/keyrings \ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y bash gnupg curl lsb-release \ && curl -fsSL https://packages.redis.io/gpg | gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg \ && echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb bookworm main" | tee /etc/apt/sources.list.d/redis.list \ - && curl -fsSL https://www.mongodb.org/static/pgp/server-4.4.asc | gpg --dearmor -o /usr/share/keyrings/mongodb-archive-keyring.gpg \ - && echo "deb [signed-by=/usr/share/keyrings/mongodb-archive-keyring.gpg] https://repo.mongodb.org/apt/debian bookworm/mongodb-org/4.4 main" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list \ + && curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | gpg --dearmor -o /usr/share/keyrings/mongodb-archive-keyring.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/mongodb-archive-keyring.gpg] https://repo.mongodb.org/apt/debian bookworm/mongodb-org/7.0 main" | tee /etc/apt/sources.list.d/mongodb-org-7.0.list \ && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends -y \ mongodb-org \ redis \ From 267b565da5dd71c56e051d43735f023ae00893d5 Mon Sep 17 00:00:00 2001 From: Ludo Mikula Date: Fri, 10 May 2024 19:15:13 +0200 Subject: [PATCH 09/12] fix: fixed saving of user profile changes --- .../org/lowcoder/domain/user/model/User.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/model/User.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/model/User.java index 821261bd8..0b0eafce7 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/model/User.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/model/User.java @@ -11,6 +11,8 @@ import lombok.*; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.ListUtils; import org.apache.commons.collections4.SetUtils; import org.apache.commons.lang3.StringUtils; import org.lowcoder.domain.mongodb.AfterMongodbRead; @@ -79,8 +81,7 @@ public class User extends HasIdAndAuditing implements BeforeMongodbWrite, AfterM /** * Only used for mongodb (de)serialization */ - @Builder.Default - private List apiKeys = new ArrayList<>(); + private List apiKeys; @Transient @JsonIgnore @@ -143,15 +144,20 @@ public void markAsDeleted() { @Override public void beforeMongodbWrite(MongodbInterceptorContext context) { - this.apiKeysList.forEach(apiKey -> apiKey.doEncrypt(s -> context.encryptionService().encryptString(s))); - apiKeys = JsonUtils.fromJsonSafely(JsonUtils.toJsonSafely(apiKeysList, SerializeConfig.JsonViews.Internal.class), new TypeReference<>() { - }, new ArrayList<>()); + if (CollectionUtils.isNotEmpty(this.apiKeysList)) { + this.apiKeysList.forEach(apiKey -> apiKey.doEncrypt(s -> context.encryptionService().encryptString(s))); + apiKeys = JsonUtils.fromJsonSafely(JsonUtils.toJsonSafely(apiKeysList, SerializeConfig.JsonViews.Internal.class), new TypeReference<>() { + }, new ArrayList<>()); + } } @Override public void afterMongodbRead(MongodbInterceptorContext context) { - this.apiKeysList = JsonUtils.fromJsonSafely(JsonUtils.toJson(apiKeys), new TypeReference<>() { - }, new ArrayList<>()); - this.apiKeysList.forEach(authConfig -> authConfig.doDecrypt(s -> context.encryptionService().decryptString(s))); + if (CollectionUtils.isNotEmpty(apiKeys)) + { + this.apiKeysList = JsonUtils.fromJsonSafely(JsonUtils.toJson(apiKeys), new TypeReference<>() { + }, new ArrayList<>()); + this.apiKeysList.forEach(authConfig -> authConfig.doDecrypt(s -> context.encryptionService().decryptString(s))); + } } } From da0c95bd02aea5742058792bab2881c53dbd2414 Mon Sep 17 00:00:00 2001 From: Ludo Mikula Date: Fri, 10 May 2024 19:15:13 +0200 Subject: [PATCH 10/12] fix: fixed saving of user profile changes --- .../org/lowcoder/domain/user/model/User.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/model/User.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/model/User.java index 0b0eafce7..9b516065a 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/model/User.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/model/User.java @@ -1,18 +1,13 @@ package org.lowcoder.domain.user.model; -import static com.google.common.base.Suppliers.memoize; -import static org.lowcoder.infra.util.AssetUtils.toAssetPath; - -import java.time.Instant; -import java.util.*; -import java.util.function.Supplier; - +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.type.TypeReference; import lombok.*; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.collections4.ListUtils; import org.apache.commons.collections4.SetUtils; import org.apache.commons.lang3.StringUtils; import org.lowcoder.domain.mongodb.AfterMongodbRead; @@ -25,9 +20,12 @@ import org.springframework.data.annotation.Transient; import org.springframework.data.mongodb.core.mapping.Document; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.Instant; +import java.util.*; +import java.util.function.Supplier; + +import static com.google.common.base.Suppliers.memoize; +import static org.lowcoder.infra.util.AssetUtils.toAssetPath; @Getter @@ -44,8 +42,7 @@ public class User extends HasIdAndAuditing implements BeforeMongodbWrite, AfterM private String name; - @Builder.Default - private String uiLanguage = UiConstants.DEFAULT_UI_LANGUAGE; + private String uiLanguage; private String avatar; @@ -159,5 +156,10 @@ public void afterMongodbRead(MongodbInterceptorContext context) { }, new ArrayList<>()); this.apiKeysList.forEach(authConfig -> authConfig.doDecrypt(s -> context.encryptionService().decryptString(s))); } + + /** set UI language to default one if it's null **/ + if (StringUtils.isBlank(this.uiLanguage)) { + this.uiLanguage = UiConstants.DEFAULT_UI_LANGUAGE; + } } } From 065f003d45704a0af01640b6441cfe4f4545ab24 Mon Sep 17 00:00:00 2001 From: Ludo Mikula Date: Sun, 12 May 2024 22:12:04 +0200 Subject: [PATCH 11/12] new: extend generic oauth configuration data --- .../lowcoder/sdk/auth/Oauth2GenericAuthConfig.java | 4 ++++ .../api/authentication/dto/AuthConfigRequest.java | 13 +++++++++++++ .../service/factory/AuthConfigFactoryImpl.java | 4 ++++ 3 files changed, 21 insertions(+) diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java index c60314dda..202e01c08 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2GenericAuthConfig.java @@ -11,9 +11,13 @@ @SuperBuilder @Jacksonized public class Oauth2GenericAuthConfig extends Oauth2SimpleAuthConfig { + private String sourceDescription; + private String sourceIcon; + private String sourceCategory; private String issuerUri; private String authorizationEndpoint; private String tokenEndpoint; private String userInfoEndpoint; private String scope; + private Boolean userInfoIntrospection; } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/dto/AuthConfigRequest.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/dto/AuthConfigRequest.java index 683abab99..93452c1f8 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/dto/AuthConfigRequest.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/dto/AuthConfigRequest.java @@ -88,7 +88,20 @@ public String getSourceName(String defaultValue) { return defaultValue; } + public String getSourceDescription() { + return getString("sourceDescription"); + } + + public String getSourceIcon() { + return getString("sourceIcon"); + } + + public String getSourceCategory() { + return getString("sourceDescription"); + } + public String getString(String key) { return MapUtils.getString(this, key); } + } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java index a19172e7d..4e9eb7f13 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java @@ -106,6 +106,9 @@ private Oauth2SimpleAuthConfig buildOauth2GenericAuthConfig(AuthConfigRequest au .enableRegister(authConfigRequest.isEnableRegister()) .source(authConfigRequest.getSource(AuthTypeConstants.GENERIC)) .sourceName(authConfigRequest.getSourceName(AuthTypeConstants.GENERIC)) + .sourceDescription(authConfigRequest.getSourceDescription()) + .sourceIcon(authConfigRequest.getSourceIcon()) + .sourceCategory(authConfigRequest.getSourceCategory()) .clientId(requireNonNull(authConfigRequest.getClientId(), "clientId can not be null.")) .clientSecret(authConfigRequest.getClientSecret()) .issuerUri(authConfigRequest.getIssuerUri()) @@ -114,6 +117,7 @@ private Oauth2SimpleAuthConfig buildOauth2GenericAuthConfig(AuthConfigRequest au .userInfoEndpoint(authConfigRequest.getUserInfoEndpoint()) .scope(authConfigRequest.getScope()) .authType(AuthTypeConstants.GENERIC) + .userInfoIntrospection(MapUtils.getBoolean(authConfigRequest,"userInfoIntrospection")) .build(); } } From 0780f4628b98fcf6b25834d87e19ef3680349e6d Mon Sep 17 00:00:00 2001 From: Ludo Mikula Date: Sun, 12 May 2024 23:03:14 +0200 Subject: [PATCH 12/12] new: added email notifications environment variables to compose files --- deploy/docker/docker-compose-multi.yaml | 11 +++++++++++ deploy/docker/docker-compose.yaml | 13 +++++++++++++ .../src/main/resources/application.yaml | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/deploy/docker/docker-compose-multi.yaml b/deploy/docker/docker-compose-multi.yaml index 14eb5c84b..b3bb6b929 100644 --- a/deploy/docker/docker-compose-multi.yaml +++ b/deploy/docker/docker-compose-multi.yaml @@ -60,6 +60,17 @@ services: # LOWCODER_API_KEY_SECRET: "5a41b090758b39b226603177ef48d73ae9839dd458ccb7e66f7e7cc028d5a50b" LOWCODER_WORKSPACE_MODE: SAAS + # Lowcoder notification emails setup + LOWCODER_ADMIN_SMTP_HOST: smtp.gmail.com + LOWCODER_ADMIN_SMTP_PORT: 587 + LOWCODER_ADMIN_SMTP_USERNAME: + LOWCODER_ADMIN_SMTP_PASSWORD: + LOWCODER_ADMIN_SMTP_AUTH: true + LOWCODER_ADMIN_SMTP_SSL_ENABLED: false + LOWCODER_ADMIN_SMTP_STARTTLS_ENABLED: true + LOWCODER_ADMIN_SMTP_STARTTLS_REQUIRED: true + # Email used as sender in lost password email + LOWCODER_EMAIL_NOTIFICATIONS_SENDER: info@localhost restart: unless-stopped depends_on: - mongodb diff --git a/deploy/docker/docker-compose.yaml b/deploy/docker/docker-compose.yaml index ca0a316eb..092f3027f 100644 --- a/deploy/docker/docker-compose.yaml +++ b/deploy/docker/docker-compose.yaml @@ -12,6 +12,8 @@ services: - "3443:3443" # - "27017:27017" environment: + # Public base url + LOWCODER_PUBLIC_URL: "http://localhost:3000/" # enable services LOWCODER_REDIS_ENABLED: "true" LOWCODER_MONGODB_ENABLED: "true" @@ -59,6 +61,17 @@ services: LOWCODER_MAX_REQUEST_SIZE: 20m LOWCODER_MAX_QUERY_TIMEOUT: 120 LOWCODER_WORKSPACE_MODE: SAAS + # Lowcoder notification emails setup + LOWCODER_ADMIN_SMTP_HOST: smtp.gmail.com + LOWCODER_ADMIN_SMTP_PORT: 587 + LOWCODER_ADMIN_SMTP_USERNAME: + LOWCODER_ADMIN_SMTP_PASSWORD: + LOWCODER_ADMIN_SMTP_AUTH: true + LOWCODER_ADMIN_SMTP_SSL_ENABLED: false + LOWCODER_ADMIN_SMTP_STARTTLS_ENABLED: true + LOWCODER_ADMIN_SMTP_STARTTLS_REQUIRED: true + # Email used as sender in lost password email + LOWCODER_EMAIL_NOTIFICATIONS_SENDER: info@localhost volumes: - ./lowcoder-stacks:/lowcoder-stacks - ./lowcoder-stacks/assets:/lowcoder/assets diff --git a/server/api-service/lowcoder-server/src/main/resources/application.yaml b/server/api-service/lowcoder-server/src/main/resources/application.yaml index 1a1ce9e51..2c2c1293e 100644 --- a/server/api-service/lowcoder-server/src/main/resources/application.yaml +++ b/server/api-service/lowcoder-server/src/main/resources/application.yaml @@ -84,7 +84,7 @@ common: marketplace: private-mode: ${LOWCODER_MARKETPLACE_PRIVATE_MODE:true} lowcoder-public-url: ${LOWCODER_PUBLIC_URL:http://localhost:8080} - notifications-email-sender: ${LOWCODER_LOST_PASSWORD_EMAIL_SENDER:info@lowcoder.org} + notifications-email-sender: ${LOWCODER_EMAIL_NOTIFICATIONS_SENDER:info@localhost} material: mongodb-grid-fs: