diff --git a/adobe-esign-connector-product/README.md b/adobe-esign-connector-product/README.md index 4342d7b..a9af233 100644 --- a/adobe-esign-connector-product/README.md +++ b/adobe-esign-connector-product/README.md @@ -16,23 +16,23 @@ YOUR DEMO DESCRIPTION GOES HERE ## Setup -To use the Adobe Sign Connector it needs to be connected with Adobe. An Adobe administration account needs to be created. +To use the Adobe Sign Connector it needs to be connected with Adobe. An Adobe administration account needs to be created. ### Creating Adobe Sign account (Company/Developer) 1. Create a **AdobeSign** Company **Account** OR for Developer Account creation use [Create Developer Account, APIs for custom applications | Acrobat Sign](https://www.adobe.com/sign/developer-form.html) an follow the steps: a. Fill form with personal and business data + continue ![fill-account-info](images/createAccountFillInfo.png) - + b. Provide a password + continue ![fill-password](images/createAccountPassword.png) - + c. Provide date of birth + continue ![fill-birth-date](images/createAccountBirthDate.png) d. You will receive a verification code. Insert the code. Will automatically continue ![verification-code](images/createAccountVerificationCode.png) - + e. Developer account is created ![account-finished](images/createAccountFinished.png) @@ -55,9 +55,9 @@ To be able to open the Admin Setup page the admin user needs to own `ADOBE_ESIGN ##### How to get Integration Key 1. Go to your Adobe Sign account page: https://secure.adobesign.com/account/ - 2. Open **Access Tokens** configuration + 2. Open **Access Tokens** configuration ![access-tokens](images/integrationKey1.png) - 3. Create new Integration Key + 3. Create new Integration Key ![create-integration-key](images/integrationKey2.png) 4. Copy the Integration Key to the Admin Setup Page ![copy-integration-key](images/integrationKey3.png) @@ -67,13 +67,13 @@ Adobe API doc references for OAuth 1. https://secure.adobesign.com/public/static/oauthDoc.jsp 2. https://opensource.adobe.com/acrobat-sign/developer_guide/oauth.html - + #### OAuth API Application setup An API Application needs to be setup at Adobe Sign admin account before OAuth can be configured in the connector. 1. Go to your Adobe Sign account page: https://secure.adobesign.com/account/ - 2. Go to **API Applications** configuration + 2. Go to **API Applications** configuration ![api-applications](images/oauth1.png) - 3. Create new API Application. Set the Name, Display Name and Domain + 3. Create new API Application. Set the Name, Display Name and Domain ![new-application](images/oauth2.png) 4. Open the newly created Application and copy ID and Secret to the connector's Admin Setup page a. Application ID = `adobe-sign-connector.clientId` @@ -90,24 +90,25 @@ An API Application needs to be setup at Adobe Sign admin account before OAuth ca |--|--|--| | adobe-sign-connector.baseUri | Base URI for getting the access and refresh access tokens (without the `/token` or `/refresh` part) | `https://api.eu2.adobesign.com/oauth/v2` | adobe-sign-connector.authenticationUri| URL for the Authorization request (:exclamation:differs from tokens URL)| `https://secure.eu2.adobesign.com/public/oauth/v2` -| adobe-sign-connector.clientId| Adobe API Application Client ID| -| adobe-sign-connector.clientSecret| Adobe API Application Client Secret | +| adobe-sign-connector.clientId| Adobe API Application Client ID| +| adobe-sign-connector.clientSecret| Adobe API Application Client Secret | | adobe-sign-connector.permissions | List of permissions that will be requested for the OAuth token | `user_read:account user_write:account user_login:account agreement_read:account agreement_write:account agreement_send:account widget_read:account widget_write:account library_read:account library_write:account workflow_read:account workflow_write:account` -| adobe-sign-connector.oauthToken | Just info about the OAuth token. Empty means there is no token initialized. To request a new token use the `Save and Request Token` button | +| adobe-sign-connector.oauthToken | Info about the OAuth refresh token. Empty means there is no token initialized. To request a new token use the `Save and Request new Token` button | +| adobe-sign-connector.accessToken| Info about the OAuth access token. | | Redirect URI | This URI just needs to be setup to the API Application at Adobe Sign account page. (see **OAuth API Application setup** section)| `https://localhost:8444/designer/pro/adobe-esign-connector/18A83631DA63DA93/oauthResume.ivp` #### Requesting OAuth token :exclamation::exclamation::exclamation: Please configure all the Variables in OAuth section on the Admin Setup page (see previous section) as they are necessary for requesting the token. - 1. Click the `Save and Request Token` button. You will be redirected to Adobe Sign login page if the configuration of the Variables is correct. + 1. Click the `Save and Request new Token` button. You will be redirected to Adobe Sign login page if the configuration of the Variables is correct. ![save-and-request-token](images/tokenRequest1.png) 2. Login with your Adobe Sign account ![adobe-login](images/tokenRequest2.png) -3. After successful login you should see all the requested permissions. Click **Allow Access**. +3. After successful login you should see all the requested permissions. Click **Allow Access**. ![request-permissions](images/tokenRequest3.png) 4. The token will be retrieved and you should be redirected back to the connector's Admin Setup page and should be able to see the initialized token. ![token](images/tokenRequest4.png) ``` @variables.yaml@ -``` \ No newline at end of file +``` diff --git a/adobe-esign-connector-product/images/adminPage.png b/adobe-esign-connector-product/images/adminPage.png index adf950a..4131954 100644 Binary files a/adobe-esign-connector-product/images/adminPage.png and b/adobe-esign-connector-product/images/adminPage.png differ diff --git a/adobe-esign-connector-product/images/tokenRequest1.png b/adobe-esign-connector-product/images/tokenRequest1.png index 7af5396..963817b 100644 Binary files a/adobe-esign-connector-product/images/tokenRequest1.png and b/adobe-esign-connector-product/images/tokenRequest1.png differ diff --git a/adobe-esign-connector-product/images/tokenRequest4.png b/adobe-esign-connector-product/images/tokenRequest4.png index ba62d37..b2f2af1 100644 Binary files a/adobe-esign-connector-product/images/tokenRequest4.png and b/adobe-esign-connector-product/images/tokenRequest4.png differ diff --git a/adobe-esign-connector/cms/cms_en.yaml b/adobe-esign-connector/cms/cms_en.yaml index aab6d87..553466b 100644 --- a/adobe-esign-connector/cms/cms_en.yaml +++ b/adobe-esign-connector/cms/cms_en.yaml @@ -11,5 +11,5 @@ Dialogs: IntegrationKeyInfo: Setting the integrationKey will disable OAuth. If you wanna use OAuth then fill the OAuth section and leave the integrationKey empty. OAuth: OAuth RedirectURI: Redirect URI - RequestToken: Save and Request Token + RequestToken: Save and Request new Token Title: Adobe Sign Admin Setup diff --git a/adobe-esign-connector/src/com/axonivy/connector/adobe/esign/connector/auth/oauth/OAuth2BearerFilter.java b/adobe-esign-connector/src/com/axonivy/connector/adobe/esign/connector/auth/oauth/OAuth2BearerFilter.java index b7d61d6..2aa0c1a 100644 --- a/adobe-esign-connector/src/com/axonivy/connector/adobe/esign/connector/auth/oauth/OAuth2BearerFilter.java +++ b/adobe-esign-connector/src/com/axonivy/connector/adobe/esign/connector/auth/oauth/OAuth2BearerFilter.java @@ -33,7 +33,8 @@ public class OAuth2BearerFilter implements javax.ws.rs.client.ClientRequestFilte private static final String TOKEN_SEPARATOR = ":"; public static final String AUTH_SCOPE_PROPERTY = "AUTH.scope"; - public static final AdobeVariable TOKEN_VAR = AdobeVariable.OAUTH_TOKEN; + public static final AdobeVariable REFRESH_TOKEN_VAR = AdobeVariable.OAUTH_TOKEN; + public static final AdobeVariable ACCESS_TOKEN_VAR = AdobeVariable.ACCESS_TOKEN; private String property; private Supplier name = null; @@ -59,22 +60,38 @@ public void filter(ClientRequestContext context) throws IOException { protected final String getAccessToken(ClientRequestContext context) { FeatureConfig config = new FeatureConfig(context.getConfiguration(), getSource()); - VarTokenStore store = VarTokenStore.get(TOKEN_VAR.getVariableName()); - var token = store.getToken(); - if (token == null || token.isExpired()) { - if (token == null || !token.hasRefreshToken()) { - token = getNewAccessToken(context.getClient(), config); - } else { - token = getRefreshedAccessToken(context.getClient(), config, token.refreshToken()); + VarTokenStore refreshTokenStore = VarTokenStore.get(REFRESH_TOKEN_VAR.getVariableName()); + var refreshToken = refreshTokenStore.getToken(); + + VarTokenStore accessTokenStore = VarTokenStore.get(ACCESS_TOKEN_VAR.getVariableName()); + var accessToken = accessTokenStore.getToken(); + + String resultToken = null; + + if(accessToken == null || accessToken.isExpired()) { + // refresh access token + if(refreshToken != null && refreshToken.hasRefreshToken()) { + accessToken = getRefreshedAccessToken(context.getClient(), config, refreshToken.refreshToken()); + accessTokenStore.setToken(accessToken); + resultToken = accessToken.accessToken(); } - store.setToken(token); // keep for following requests + else { // get new access token + refreshToken = getNewAccessToken(context.getClient(), config); + refreshTokenStore.setToken(refreshToken); + accessTokenStore.setToken(refreshToken); + resultToken = refreshToken.accessToken(); + } + } + else { // use existing token + resultToken = accessToken.accessToken(); } - if (!token.hasAccessToken()) { - store.setToken(null); - authError().withMessage("Failed to read 'access_token' from " + token).throwError(); + + if (accessToken != null && !accessToken.hasAccessToken()) { + accessTokenStore.setToken(null); + authError().withMessage("Failed to read 'access_token' from " + refreshToken).throwError(); } - return token.accessToken(); + return resultToken; } String createKey(FeatureConfig config) { diff --git a/adobe-esign-connector/src/com/axonivy/connector/adobe/esign/connector/enums/AdobeVariable.java b/adobe-esign-connector/src/com/axonivy/connector/adobe/esign/connector/enums/AdobeVariable.java index b4ad58f..7aed7a2 100644 --- a/adobe-esign-connector/src/com/axonivy/connector/adobe/esign/connector/enums/AdobeVariable.java +++ b/adobe-esign-connector/src/com/axonivy/connector/adobe/esign/connector/enums/AdobeVariable.java @@ -18,6 +18,7 @@ public enum AdobeVariable { USE_USER_PASS_FLOW_USER("adobe-sign-connector.useUserPassFlow.user"), USE_USER_PASS_FLOW_PASS("adobe-sign-connector.useUserPassFlow.pass"), OAUTH_TOKEN("adobe-sign-connector.oauthToken"), + ACCESS_TOKEN("adobe-sign-connector.accessToken"), AUTHENTICATION_URI("adobe-sign-connector.authenticationUri"); private String variableName; diff --git a/adobe-esign-connector/src/com/axonivy/connector/adobe/esign/connector/service/AdminSetupService.java b/adobe-esign-connector/src/com/axonivy/connector/adobe/esign/connector/service/AdminSetupService.java index fcbd5ea..033efcc 100644 --- a/adobe-esign-connector/src/com/axonivy/connector/adobe/esign/connector/service/AdminSetupService.java +++ b/adobe-esign-connector/src/com/axonivy/connector/adobe/esign/connector/service/AdminSetupService.java @@ -19,7 +19,6 @@ import com.axonivy.connector.adobe.esign.connector.AdminSetup.AdminSetupData; import com.axonivy.connector.adobe.esign.connector.auth.OAuth2Feature.AccessTokenRequest; -import com.axonivy.connector.adobe.esign.connector.auth.OAuth2Feature.RefreshTokenRequest; import com.axonivy.connector.adobe.esign.connector.auth.oauth.OAuth2UriProperty; import com.axonivy.connector.adobe.esign.connector.auth.oauth.Token; import com.axonivy.connector.adobe.esign.connector.auth.oauth.VarTokenStore; @@ -45,6 +44,7 @@ public static void initVars(AdminSetupData data) { data.setOauthToken(AdobeVariable.OAUTH_TOKEN.getValue()); data.setPermissions(AdobeVariable.PERMISSIONS.getValue()); data.setReturnPage(AdobeVariable.RETURN_PAGE.getValue()); + data.setAccessToken(AdobeVariable.ACCESS_TOKEN.getValue()); } /** @@ -60,8 +60,7 @@ public static void updateVars(AdminSetupData data) { AdobeVariable.INTEGRATION_KEY.updateValue(data.getIntegrationKey()); AdobeVariable.PERMISSIONS.updateValue(data.getPermissions()); AdobeVariable.RETURN_PAGE.updateValue(data.getReturnPage()); - // dont updateW oauth token variable - AdobeVariable.OAUTH_TOKEN.updateValue(data.getOauthToken()); + // dont update oauth token variables } /** @@ -100,27 +99,29 @@ public static void getNewAccessToken(String authCode) throws URISyntaxException var clientSecret = AdobeVariable.CLIENT_SECRET.getValue(); UriBuilder tokenBaseUri = UriBuilder.fromUri(new URI(AdobeVariable.BASE_URI.getValue())); - VarTokenStore store = VarTokenStore.get(AdobeVariable.OAUTH_TOKEN.getVariableName()); - Token token = store.getToken(); + // get token stores for refresh and access tokens + VarTokenStore refreshTokenStore = VarTokenStore.get(AdobeVariable.OAUTH_TOKEN.getVariableName()); + VarTokenStore accessTokenStore = VarTokenStore.get(AdobeVariable.ACCESS_TOKEN.getVariableName()); + //request new token Client client = ClientBuilder.newClient(); - Response response = null; - if (token == null || !token.hasRefreshToken()) { - tokenBaseUri.path(OAuth2UriProperty.TOKEN_RELATIVE_PATH); - AccessTokenRequest authRequest = new AccessTokenRequest(authCode, clientId, clientSecret, - createRedirectUrl()); - WebTarget target = client.target(tokenBaseUri); - response = target.request().post(Entity.form(authRequest.paramsMap())); - } else { - tokenBaseUri.path(OAuth2UriProperty.REFRESH_RELATIVE_PATH); - RefreshTokenRequest authRequest = new RefreshTokenRequest(token.refreshToken(), clientId, clientSecret); - WebTarget target = client.target(tokenBaseUri); - response = target.request().post(Entity.form(authRequest.paramsMap())); - } + tokenBaseUri.path(OAuth2UriProperty.TOKEN_RELATIVE_PATH); + AccessTokenRequest authRequest = new AccessTokenRequest(authCode, clientId, clientSecret, + createRedirectUrl()); + WebTarget target = client.target(tokenBaseUri); + Response response = target.request().post(Entity.form(authRequest.paramsMap())); +// else { +// tokenBaseUri.path(OAuth2UriProperty.REFRESH_RELATIVE_PATH); +// RefreshTokenRequest authRequest = new RefreshTokenRequest(refreshToken.refreshToken(), clientId, clientSecret); +// WebTarget target = client.target(tokenBaseUri); +// response = target.request().post(Entity.form(authRequest.paramsMap())); +// } if (response.getStatusInfo().getFamily() == Family.SUCCESSFUL) { GenericType> map = new GenericType<>(Map.class); + // store new token Token newToken = new Token(response.readEntity(map)); - store.setToken(newToken); + refreshTokenStore.setToken(newToken); + accessTokenStore.setToken(newToken); } else { Ivy.log().error("failed to get access token: " + response); } diff --git a/adobe-esign-connector/src_hd/com/axonivy/connector/adobe/esign/connector/AdminSetup/AdminSetup.xhtml b/adobe-esign-connector/src_hd/com/axonivy/connector/adobe/esign/connector/AdminSetup/AdminSetup.xhtml index 0a75992..ca0f296 100644 --- a/adobe-esign-connector/src_hd/com/axonivy/connector/adobe/esign/connector/AdminSetup/AdminSetup.xhtml +++ b/adobe-esign-connector/src_hd/com/axonivy/connector/adobe/esign/connector/AdminSetup/AdminSetup.xhtml @@ -125,6 +125,17 @@ actionListener="#{logic.requestToken}"/> +
+
+ +
+
+ + +
+