diff --git a/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/OAuth2AuthManagerImpl.java b/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/OAuth2AuthManagerImpl.java index c3bad43be40e..a5f5f827d773 100644 --- a/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/OAuth2AuthManagerImpl.java +++ b/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/OAuth2AuthManagerImpl.java @@ -168,6 +168,7 @@ public OauthProviderVO registerOauthProvider(RegisterOAuthProviderCmd cmd) { Long domainId = normalizeGlobalScope(resolveDomainIdFromIdOrPath(cmd.getDomainId(), cmd.getDomainPath())); String authorizeUrl = StringUtils.trim(cmd.getAuthorizeUrl()); String tokenUrl = StringUtils.trim(cmd.getTokenUrl()); + Boolean enabled = cmd.getEnabled(); if (!isOAuthPluginEnabled(domainId)) { throw new CloudRuntimeException("OAuth is not enabled, please enable to register"); @@ -183,7 +184,7 @@ public OauthProviderVO registerOauthProvider(RegisterOAuthProviderCmd cmd) { } } - return saveOauthProvider(provider, description, clientId, secretKey, redirectUri, authorizeUrl, tokenUrl, domainId); + return saveOauthProvider(provider, description, clientId, secretKey, redirectUri, authorizeUrl, tokenUrl, domainId, enabled); } @Override @@ -271,7 +272,7 @@ public OauthProviderVO updateOauthProvider(UpdateOAuthProviderCmd cmd) { return _oauthProviderDao.findById(id); } - private OauthProviderVO saveOauthProvider(String provider, String description, String clientId, String secretKey, String redirectUri, String authorizeUrl, String tokenUrl, Long domainId) { + private OauthProviderVO saveOauthProvider(String provider, String description, String clientId, String secretKey, String redirectUri, String authorizeUrl, String tokenUrl, Long domainId, Boolean enabled) { final OauthProviderVO oauthProviderVO = new OauthProviderVO(); oauthProviderVO.setProvider(provider); @@ -282,7 +283,7 @@ private OauthProviderVO saveOauthProvider(String provider, String description, S oauthProviderVO.setDomainId(domainId); oauthProviderVO.setAuthorizeUrl(authorizeUrl); oauthProviderVO.setTokenUrl(tokenUrl); - oauthProviderVO.setEnabled(true); + oauthProviderVO.setEnabled(enabled == null || enabled); _oauthProviderDao.persist(oauthProviderVO); diff --git a/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/RegisterOAuthProviderCmd.java b/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/RegisterOAuthProviderCmd.java index 79274ba904b1..54f03ccb8d98 100644 --- a/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/RegisterOAuthProviderCmd.java +++ b/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/RegisterOAuthProviderCmd.java @@ -14,7 +14,9 @@ // limitations under the License. package org.apache.cloudstack.oauth2.api.command; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Map; import javax.inject.Inject; @@ -28,6 +30,7 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.auth.UserOAuth2Authenticator; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.oauth2.OAuth2AuthManager; import org.apache.cloudstack.oauth2.api.response.OauthProviderResponse; @@ -76,6 +79,9 @@ public class RegisterOAuthProviderCmd extends BaseCmd { @Parameter(name = ApiConstants.TOKEN_URL, type = CommandType.STRING, description = "Token URL for OAuth finalization (only required for keycloak provider)") private String tokenUrl; + @Parameter(name = ApiConstants.ENABLED, type = CommandType.BOOLEAN, description = "OAuth provider will be enabled or disabled based on this value", since = "4.24.0") + private Boolean enabled; + @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, description = "Any OAuth provider details in key/value pairs using format details[i].keyname=keyvalue. Example: details[0].clientsecret=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") protected Map details; @@ -121,6 +127,10 @@ public String getTokenUrl() { return tokenUrl; } + public Boolean getEnabled() { + return enabled; + } + public Map getDetails() { if (MapUtils.isEmpty(details)) { return null; @@ -151,6 +161,22 @@ public void execute() throws ServerApiException, ConcurrentOperationException, E provider.getAuthorizeUrl(), provider.getTokenUrl(), domain); response.setResponseName(getCommandName()); response.setObjectName(ApiConstants.OAUTH_PROVIDER); + + List userOAuth2AuthenticatorPlugins = _oauth2mgr.listUserOAuth2AuthenticationProviders(); + List authenticatorPluginNames = new ArrayList<>(); + + for (UserOAuth2Authenticator authenticator : userOAuth2AuthenticatorPlugins) { + String name = authenticator.getName(); + authenticatorPluginNames.add(name); + } + + boolean oauthEnabled = OAuth2AuthManager.isPluginEnabledForDomain(provider.getDomainId()); + if (oauthEnabled && authenticatorPluginNames.contains(provider.getProvider()) && provider.isEnabled()) { + response.setEnabled(true); + } else { + response.setEnabled(false); + } + setResponseObject(response); } } diff --git a/plugins/user-authenticators/oauth2/src/test/java/org/apache/cloudstack/oauth2/OAuth2AuthManagerImplTest.java b/plugins/user-authenticators/oauth2/src/test/java/org/apache/cloudstack/oauth2/OAuth2AuthManagerImplTest.java index e3e8f7594b37..ffbfa6db6210 100644 --- a/plugins/user-authenticators/oauth2/src/test/java/org/apache/cloudstack/oauth2/OAuth2AuthManagerImplTest.java +++ b/plugins/user-authenticators/oauth2/src/test/java/org/apache/cloudstack/oauth2/OAuth2AuthManagerImplTest.java @@ -49,6 +49,7 @@ import java.util.Map; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doNothing; @@ -120,6 +121,29 @@ public void testRegisterOauthProvider() { assertEquals("testSecretKey", result.getSecretKey()); } + @Test + public void testRegisterOauthProviderDisabledWhenRequested() { + when(_authManager.isOAuthPluginEnabled(Mockito.nullable(Long.class))).thenReturn(true); + + RegisterOAuthProviderCmd cmd = Mockito.mock(RegisterOAuthProviderCmd.class); + when(cmd.getDescription()).thenReturn("test description"); + when(cmd.getProvider()).thenReturn("github"); + when(cmd.getClientId()).thenReturn("client-id"); + when(cmd.getSecretKey()).thenReturn("secret-key"); + when(cmd.getRedirectUri()).thenReturn("http://localhost"); + when(cmd.getAuthorizeUrl()).thenReturn("https://auth.example.com"); + when(cmd.getTokenUrl()).thenReturn("https://token.example.com"); + when(cmd.getDomainId()).thenReturn(null); + when(cmd.getDomainPath()).thenReturn(null); + when(cmd.getEnabled()).thenReturn(false); + when(_authManager._oauthProviderDao.findByProviderAndDomain("github", null)).thenReturn(null); + when(_authManager._oauthProviderDao.persist(Mockito.any(OauthProviderVO.class))).thenAnswer(i -> i.getArgument(0)); + + OauthProviderVO result = _authManager.registerOauthProvider(cmd); + + assertFalse(result.isEnabled()); + } + @Test public void testUpdateOauthProvider() { Long id = 1L; diff --git a/plugins/user-authenticators/oauth2/src/test/java/org/apache/cloudstack/oauth2/api/command/RegisterOAuthProviderCmdTest.java b/plugins/user-authenticators/oauth2/src/test/java/org/apache/cloudstack/oauth2/api/command/RegisterOAuthProviderCmdTest.java index 7e1a96e0c1ea..9a98cdf97305 100644 --- a/plugins/user-authenticators/oauth2/src/test/java/org/apache/cloudstack/oauth2/api/command/RegisterOAuthProviderCmdTest.java +++ b/plugins/user-authenticators/oauth2/src/test/java/org/apache/cloudstack/oauth2/api/command/RegisterOAuthProviderCmdTest.java @@ -20,12 +20,16 @@ package org.apache.cloudstack.oauth2.api.command; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.util.Collections; + import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.auth.UserOAuth2Authenticator; import org.apache.cloudstack.oauth2.OAuth2AuthManager; import org.apache.cloudstack.oauth2.api.response.OauthProviderResponse; import org.apache.cloudstack.oauth2.vo.OauthProviderVO; @@ -38,7 +42,7 @@ public class RegisterOAuthProviderCmdTest { private RegisterOAuthProviderCmd _cmd; @Before - public void setUp() throws Exception { + public void setUp() { _oauth2mgr = mock(OAuth2AuthManager.class); _cmd = new RegisterOAuthProviderCmd(); _cmd._oauth2mgr = _oauth2mgr; @@ -54,9 +58,35 @@ public void testExecute() throws ServerApiException { when(provider.getClientId()).thenReturn("client-id"); when(provider.getSecretKey()).thenReturn("secret-key"); when(provider.getRedirectUri()).thenReturn("http://localhost"); + when(provider.isEnabled()).thenReturn(true); when(_oauth2mgr.registerOauthProvider(any(RegisterOAuthProviderCmd.class))).thenReturn(provider); + UserOAuth2Authenticator authenticator = mock(UserOAuth2Authenticator.class); + when(authenticator.getName()).thenReturn("github"); + when(_oauth2mgr.listUserOAuth2AuthenticationProviders()).thenReturn(Collections.singletonList(authenticator)); _cmd.execute(); assertEquals(ApiConstants.OAUTH_PROVIDER, ((OauthProviderResponse)_cmd.getResponseObject()).getObjectName()); } + + @Test + public void testExecuteSetsDisabledProviderResponseWhenProviderIsDisabled() throws ServerApiException { + OauthProviderVO provider = mock(OauthProviderVO.class); + when(provider.getDomainId()).thenReturn(null); + when(provider.getUuid()).thenReturn("test-uuid"); + when(provider.getProvider()).thenReturn("github"); + when(provider.getDescription()).thenReturn("test"); + when(provider.getClientId()).thenReturn("client-id"); + when(provider.getSecretKey()).thenReturn("secret-key"); + when(provider.getRedirectUri()).thenReturn("http://localhost"); + when(provider.isEnabled()).thenReturn(false); + when(_oauth2mgr.registerOauthProvider(any(RegisterOAuthProviderCmd.class))).thenReturn(provider); + UserOAuth2Authenticator authenticator = mock(UserOAuth2Authenticator.class); + when(authenticator.getName()).thenReturn("github"); + when(_oauth2mgr.listUserOAuth2AuthenticationProviders()).thenReturn(Collections.singletonList(authenticator)); + + _cmd.execute(); + OauthProviderResponse response = (OauthProviderResponse)_cmd.getResponseObject(); + assertEquals(ApiConstants.OAUTH_PROVIDER, response.getObjectName()); + assertFalse(response.getEnabled()); + } }