diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-oauth2-provider-bundle/nifi-oauth2-provider-service/src/main/java/org/apache/nifi/oauth2/StandardOauth2AccessTokenProvider.java b/nifi-nar-bundles/nifi-standard-services/nifi-oauth2-provider-bundle/nifi-oauth2-provider-service/src/main/java/org/apache/nifi/oauth2/StandardOauth2AccessTokenProvider.java index af3a96dd68..6c2679a427 100644 --- a/nifi-nar-bundles/nifi-standard-services/nifi-oauth2-provider-bundle/nifi-oauth2-provider-service/src/main/java/org/apache/nifi/oauth2/StandardOauth2AccessTokenProvider.java +++ b/nifi-nar-bundles/nifi-standard-services/nifi-oauth2-provider-bundle/nifi-oauth2-provider-service/src/main/java/org/apache/nifi/oauth2/StandardOauth2AccessTokenProvider.java @@ -29,13 +29,16 @@ import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.annotation.lifecycle.OnDisabled; import org.apache.nifi.annotation.lifecycle.OnEnabled; import org.apache.nifi.components.AllowableValue; +import org.apache.nifi.components.ConfigVerificationResult; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.components.ValidationContext; import org.apache.nifi.components.ValidationResult; import org.apache.nifi.components.Validator; import org.apache.nifi.controller.AbstractControllerService; import org.apache.nifi.controller.ConfigurationContext; +import org.apache.nifi.controller.VerifiableControllerService; import org.apache.nifi.expression.ExpressionLanguageScope; +import org.apache.nifi.logging.ComponentLog; import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.processor.util.StandardValidators; import org.apache.nifi.ssl.SSLContextService; @@ -50,12 +53,13 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; @Tags({"oauth2", "provider", "authorization", "access token", "http"}) @CapabilityDescription("Provides OAuth 2.0 access tokens that can be used as Bearer authorization header in HTTP requests." + " Uses Resource Owner Password Credentials Grant.") -public class StandardOauth2AccessTokenProvider extends AbstractControllerService implements OAuth2AccessTokenProvider { +public class StandardOauth2AccessTokenProvider extends AbstractControllerService implements OAuth2AccessTokenProvider, VerifiableControllerService { public static final PropertyDescriptor AUTHORIZATION_SERVER_URL = new PropertyDescriptor.Builder() .name("authorization-server-url") .displayName("Authorization Server URL") @@ -338,4 +342,20 @@ public class StandardOauth2AccessTokenProvider extends AbstractControllerService return Instant.now().isAfter(expirationRefreshTime); } + + @Override + public List verify(ConfigurationContext context, ComponentLog verificationLogger, Map variables) { + ConfigVerificationResult.Builder builder = new ConfigVerificationResult.Builder() + .verificationStepName("Can acquire token"); + + try { + getAccessDetails(); + builder.outcome(ConfigVerificationResult.Outcome.SUCCESSFUL); + } catch (Exception ex) { + builder.outcome(ConfigVerificationResult.Outcome.FAILED) + .explanation(ex.getMessage()); + } + + return Arrays.asList(builder.build()); + } } diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-oauth2-provider-bundle/nifi-oauth2-provider-service/src/test/java/org/apache/nifi/oauth2/StandardOauth2AccessTokenProviderTest.java b/nifi-nar-bundles/nifi-standard-services/nifi-oauth2-provider-bundle/nifi-oauth2-provider-service/src/test/java/org/apache/nifi/oauth2/StandardOauth2AccessTokenProviderTest.java index 20054bcad3..9aa1d5006d 100644 --- a/nifi-nar-bundles/nifi-standard-services/nifi-oauth2-provider-bundle/nifi-oauth2-provider-service/src/test/java/org/apache/nifi/oauth2/StandardOauth2AccessTokenProviderTest.java +++ b/nifi-nar-bundles/nifi-standard-services/nifi-oauth2-provider-bundle/nifi-oauth2-provider-service/src/test/java/org/apache/nifi/oauth2/StandardOauth2AccessTokenProviderTest.java @@ -22,10 +22,16 @@ import okhttp3.Protocol; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; +import org.apache.nifi.components.ConfigVerificationResult; +import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.controller.ConfigurationContext; +import org.apache.nifi.controller.VerifiableControllerService; import org.apache.nifi.logging.ComponentLog; import org.apache.nifi.processor.Processor; import org.apache.nifi.processor.exception.ProcessException; +import org.apache.nifi.util.MockConfigurationContext; +import org.apache.nifi.util.MockControllerServiceLookup; +import org.apache.nifi.util.MockVariableRegistry; import org.apache.nifi.util.NoOpProcessor; import org.apache.nifi.util.TestRunner; import org.apache.nifi.util.TestRunners; @@ -43,10 +49,14 @@ import java.io.UncheckedIOException; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import static org.apache.nifi.components.ConfigVerificationResult.Outcome.FAILED; +import static org.apache.nifi.components.ConfigVerificationResult.Outcome.SUCCESSFUL; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -162,6 +172,58 @@ public class StandardOauth2AccessTokenProviderTest { assertEquals(accessTokenValue, actual); } + @Test + public void testVerifySuccess() throws Exception { + Processor processor = new NoOpProcessor(); + TestRunner runner = TestRunners.newTestRunner(processor); + runner.addControllerService("testSubject", testSubject); + + Map properties = ((MockControllerServiceLookup) runner.getProcessContext().getControllerServiceLookup()) + .getControllerServices().get("testSubject").getProperties(); + + String accessTokenValue = "access_token_value"; + + // GIVEN + Response response = buildResponse( + HTTP_OK, + "{ \"access_token\":\"" + accessTokenValue + "\" }" + ); + + when(mockHttpClient.newCall(any(Request.class)).execute()).thenReturn(response); + + final List results = ((VerifiableControllerService) testSubject).verify( + new MockConfigurationContext(testSubject, properties, runner.getProcessContext().getControllerServiceLookup(), new MockVariableRegistry()), + runner.getLogger(), + Collections.emptyMap() + ); + + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals(SUCCESSFUL, results.get(0).getOutcome()); + } + + @Test + public void testVerifyError() throws Exception { + Processor processor = new NoOpProcessor(); + TestRunner runner = TestRunners.newTestRunner(processor); + runner.addControllerService("testSubject", testSubject); + + Map properties = ((MockControllerServiceLookup) runner.getProcessContext().getControllerServiceLookup()) + .getControllerServices().get("testSubject").getProperties(); + + when(mockHttpClient.newCall(any(Request.class)).execute()).thenThrow(new IOException()); + + final List results = ((VerifiableControllerService) testSubject).verify( + new MockConfigurationContext(testSubject, properties, runner.getProcessContext().getControllerServiceLookup(), new MockVariableRegistry()), + runner.getLogger(), + Collections.emptyMap() + ); + + assertNotNull(results); + assertEquals(1, results.size()); + assertEquals(FAILED, results.get(0).getOutcome()); + } + @Test public void testRefreshToken() throws Exception { // GIVEN