A hacky approach to limiting the Google OAuth2 to a set of custom domains.
This is not the prettiest way to do it. Ideally, we should send a query parameter to Google with key "hd=example.com" in order to get Google to list accounts with only those domains. For now, we send an error when the domains don't match in a custom `ClientUserRepository` function.
This commit is contained in:
parent
b5e05e72c6
commit
9c47e1cb2f
|
|
@ -3,6 +3,8 @@ package com.appsmith.server.configurations;
|
|||
import com.appsmith.server.domains.LoginSource;
|
||||
import com.appsmith.server.domains.User;
|
||||
import com.appsmith.server.domains.UserState;
|
||||
import com.appsmith.server.exceptions.AppsmithError;
|
||||
import com.appsmith.server.exceptions.AppsmithException;
|
||||
import com.appsmith.server.services.OrganizationService;
|
||||
import com.appsmith.server.services.UserService;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
|
@ -10,7 +12,9 @@ import org.springframework.security.core.Authentication;
|
|||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.WebSessionServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebSession;
|
||||
|
|
@ -39,18 +43,24 @@ import java.util.Map;
|
|||
* saveAuthorizedClient is called on every successful OAuth2 authentication, this solves the problem
|
||||
* of plugging a handler for the same purpose.
|
||||
*/
|
||||
@Configuration
|
||||
@Component
|
||||
public class ClientUserRepository implements ServerOAuth2AuthorizedClientRepository {
|
||||
|
||||
private static final String DEFAULT_AUTHORIZED_CLIENTS_ATTR_NAME =
|
||||
WebSessionServerOAuth2AuthorizedClientRepository.class.getName() + ".AUTHORIZED_CLIENTS";
|
||||
|
||||
private final String sessionAttributeName = DEFAULT_AUTHORIZED_CLIENTS_ATTR_NAME;
|
||||
|
||||
UserService userService;
|
||||
|
||||
OrganizationService organizationService;
|
||||
|
||||
public ClientUserRepository(UserService userService, OrganizationService organizationService) {
|
||||
CommonConfig commonConfig;
|
||||
|
||||
public ClientUserRepository(UserService userService, OrganizationService organizationService, CommonConfig commonConfig) {
|
||||
this.userService = userService;
|
||||
this.organizationService = organizationService;
|
||||
this.commonConfig = commonConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -69,6 +79,19 @@ public class ClientUserRepository implements ServerOAuth2AuthorizedClientReposit
|
|||
ServerWebExchange exchange) {
|
||||
Assert.notNull(authorizedClient, "authorizedClient cannot be null");
|
||||
Assert.notNull(exchange, "exchange cannot be null");
|
||||
Assert.notNull(principal, "authentication object cannot be null");
|
||||
|
||||
// Check if the list of configured custom domains match the authenticated principal.
|
||||
// This is to provide more control over which accounts can be used to access the application.
|
||||
// TODO: This is not a good way to do this. Ideally, we should pass "hd=example.com" to OAuth2 provider to list relevant accounts only
|
||||
if(!commonConfig.getAllowedDomains().isEmpty()) {
|
||||
DefaultOidcUser userPrincipal = (DefaultOidcUser) principal.getPrincipal();
|
||||
String domain = (String) userPrincipal.getAttributes().getOrDefault("hd", "");
|
||||
if(!commonConfig.getAllowedDomains().contains(domain)) {
|
||||
return Mono.error(new AppsmithException(AppsmithError.UNAUTHORIZED_DOMAIN));
|
||||
}
|
||||
}
|
||||
|
||||
return exchange.getSession()
|
||||
.doOnSuccess(session -> {
|
||||
Map<String, OAuth2AuthorizedClient> authorizedClients = getAuthorizedClients(session);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package com.appsmith.server.configurations;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import reactor.core.scheduler.Scheduler;
|
||||
|
|
@ -7,12 +10,18 @@ import reactor.core.scheduler.Schedulers;
|
|||
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Configuration
|
||||
public class CommonConfig {
|
||||
|
||||
private String ELASTIC_THREAD_POOL_NAME = "appsmith-elastic-pool";
|
||||
|
||||
@Value("#{'${oauth2.allowed-domains}'.split(',')}")
|
||||
private List<String> allowedDomains;
|
||||
|
||||
@Bean
|
||||
public Scheduler scheduler() {
|
||||
return Schedulers.newElastic(ELASTIC_THREAD_POOL_NAME);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ public class SecurityConfig {
|
|||
@Autowired
|
||||
private OrganizationService organizationService;
|
||||
|
||||
@Autowired
|
||||
private CommonConfig commonConfig;
|
||||
|
||||
/**
|
||||
* This configuration enables CORS requests for the most common HTTP Methods
|
||||
*
|
||||
|
|
@ -72,7 +75,7 @@ public class SecurityConfig {
|
|||
.authenticated()
|
||||
.and().httpBasic()
|
||||
.and().oauth2Login()
|
||||
.authorizedClientRepository(new ClientUserRepository(userService, organizationService))
|
||||
.authorizedClientRepository(new ClientUserRepository(userService, organizationService, commonConfig))
|
||||
.and().formLogin()
|
||||
.and().build();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ public enum AppsmithError {
|
|||
PLUGIN_NOT_INSTALLED(400, 4001, "Plugin {0} not installed"),
|
||||
PLUGIN_ID_NOT_GIVEN(400, 4002, "Missing plugin id. Please input correct plugin id"),
|
||||
RESOURCE_ID_NOT_GIVEN(400, 4003, "Missing resource id. Please input correct resource id"),
|
||||
UNAUTHORIZED_DOMAIN(401, 4001, "Invalid email domain provided. Please sign in with a valid work email ID"),
|
||||
INTERNAL_SERVER_ERROR(500, 5000, "Internal server error while processing request");
|
||||
|
||||
private Integer httpErrorCode;
|
||||
|
|
|
|||
|
|
@ -19,5 +19,5 @@ jdbc.postgres.password=root
|
|||
spring.security.oauth2.client.registration.google.client-id=869021686091-9b84bbf7ea683t1aaefqnmefcnmk6fq6.apps.googleusercontent.com
|
||||
spring.security.oauth2.client.registration.google.client-secret=9dvITt4OayEY1HfeY8bHX74p
|
||||
|
||||
#Hard coded organization properties
|
||||
organization.id=5d64f1f594a5d31b3ee9ca16
|
||||
# Accounts from specific domains are allowed to login
|
||||
oauth2.allowed-domains=appsmith.com
|
||||
|
|
@ -17,5 +17,5 @@ jdbc.postgres.password=09275163cd7e737baf4c210b5e8db8ed88ddb7a0ee9acc82416fd7534
|
|||
spring.security.oauth2.client.registration.google.client-id=869021686091-9b84bbf7ea683t1aaefqnmefcnmk6fq6.apps.googleusercontent.com
|
||||
spring.security.oauth2.client.registration.google.client-secret=9dvITt4OayEY1HfeY8bHX74p
|
||||
|
||||
#Hard coded organization properties
|
||||
organization.id=5d3e90a2dfec7c00047a81ea
|
||||
# Accounts from specific domains are allowed to login
|
||||
oauth2.allowed-domains=appsmith.com
|
||||
|
|
@ -12,7 +12,4 @@ spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
|
|||
spring.jpa.show-sql=true
|
||||
|
||||
# Jackson Properties
|
||||
spring.jackson.default-property-inclusion=non_null
|
||||
|
||||
#Hard coded organization properties
|
||||
organization.id=5d5e7c29006cb4e82ea75075
|
||||
spring.jackson.default-property-inclusion=non_null
|
||||
Loading…
Reference in New Issue
Block a user