Skip to content

Commit 443e4d9

Browse files
authored
Expose Abstraction for handling authentication, add support for access_token/refresh_token authentication schemes (#69)
* extremely rough abstraction for handling authentication * start cleaning up * start cleaning up * more cleanup * add refresh_token auth method * update docs * add SsoAccessTokenSessionRefreshHandler
1 parent 8f456a7 commit 443e4d9

28 files changed

+1658
-353
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
The format is based on [Keep a Changelog](http://keepachangelog.com/)
33
and this project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## 3.2.0 (02/09/2021)
6+
- [ISSUE-68](https://github.com/Crim/pardot-java-client/issues/68) Add authentication method for grant_type=authorization_code using previously retrieved refresh_token. See `ConfigurationBuilder.withSsoRefreshTokenLogin()`
7+
- [ISSUE-70](https://github.com/Crim/pardot-java-client/issues/70) Adds ability to override the OAuth authentication endpoint when doing SSO authentication. See optional parameter `AuthorizationServer` on the `ConfigurationBuilder.withSsoRefreshTokenLogin()` and `ConfigurationBuilder.withSsoLogin()` methods.
8+
59
## 3.1.0 (10/23/2020)
610
- [ISSUE-65](https://github.com/Crim/pardot-java-client/issues/65) Adds missing Query options to `ProspectQuerytRequest` for `withUpdatedAfter()` and `withUpdatedBefore()`.
711

README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ This client library is released on Maven Central. Add a new dependency to your
3030
<dependency>
3131
<groupId>com.darksci</groupId>
3232
<artifactId>pardot-api-client</artifactId>
33-
<version>3.1.0</version>
33+
<version>3.2.0</version>
3434
</dependency>
3535
```
3636

@@ -43,6 +43,7 @@ Example Code using Salesforce SSO Authentication:
4343
* such as using an outbound proxy (authenticated or not).
4444
*/
4545
final ConfigurationBuilder configuration = Configuration.newBuilder()
46+
// This configures the client using the 'password' authentication flow.
4647
.withSsoLogin(
4748
"YourSalesforceUsername",
4849
"YourSalesforcePassword",
@@ -51,6 +52,19 @@ final ConfigurationBuilder configuration = Configuration.newBuilder()
5152
"YourPardotBusinessUnitId"
5253
);
5354

55+
/*
56+
* Alternatively, if you want to use the authorization_code authentication flow,
57+
* you can configure the client using a previously acquired refresh_token:
58+
*/
59+
Configuration.newBuilder()
60+
// This configures the client using the 'authorization_code' authentication flow.
61+
.withSsoRefreshTokenLogin(
62+
"PreviousAcquiredRefreshTokenHere",
63+
"YourConnectedAppClientId",
64+
"YourConnectedAppClientSecret",
65+
"YourPardotBusinessUnitId"
66+
);
67+
5468
/*
5569
* Optionally you can explicitly select which API version to use. If none is explicitly selected
5670
* the library will default to version 3, but the library will automatically upgrade to version
@@ -110,7 +124,9 @@ try (final PardotClient client = new PardotClient(configuration)) {
110124
Official Documentation: [Authentication](https://developer.pardot.com/kb/authentication/)
111125

112126
- Authenticating with Pardot's API using your Salesforce SSO Username, Password, and Connected Application details. [See Example](src/main/java/com/darksci/pardot/api/Example.java#L37).
113-
- Legacy authentication using your Pardot Username, Password, and User Token. [See Example](src/main/java/com/darksci/pardot/api/Example.java#L98).
127+
- Authenticating with Pardot's API using a Salesforce SSO refresh_token and Connected Application details. [See Example](src/main/java/com/darksci/pardot/api/Example.java#L103).
128+
- Authenticating with Pardot's API using Salesforce SSO against Test / Sandbox orgs. [See Example](src/main/java/com/darksci/pardot/api/Example.java#L155).
129+
- Legacy authentication using your Pardot Username, Password, and User Token. [See Example](src/main/java/com/darksci/pardot/api/Example.java#L196).
114130

115131
### Accounts
116132
Official Documentation: [Accounts](http://developer.pardot.com/kb/api-version-3/accounts/)

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.darksci</groupId>
88
<artifactId>pardot-api-client</artifactId>
9-
<version>3.1.0</version>
9+
<version>3.2.0</version>
1010
<packaging>jar</packaging>
1111

1212
<!-- Require Maven 3.5.0 -->

src/main/java/com/darksci/pardot/api/ConfigurationBuilder.java

Lines changed: 113 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,30 @@
1717

1818
package com.darksci.pardot.api;
1919

20+
import com.darksci.pardot.api.auth.AuthorizationServer;
21+
import com.darksci.pardot.api.auth.PasswordSessionRefreshHandler;
22+
import com.darksci.pardot.api.auth.SessionRefreshHandler;
23+
import com.darksci.pardot.api.auth.SsoAccessTokenSessionRefreshHandler;
24+
import com.darksci.pardot.api.auth.SsoRefreshTokenSessionRefreshHandler;
25+
import com.darksci.pardot.api.auth.SsoSessionRefreshHandler;
2026
import com.darksci.pardot.api.config.Configuration;
21-
import com.darksci.pardot.api.config.LoginType;
2227
import com.darksci.pardot.api.config.PasswordLoginCredentials;
2328
import com.darksci.pardot.api.config.ProxyConfiguration;
29+
import com.darksci.pardot.api.config.SsoAccessTokenCredentials;
2430
import com.darksci.pardot.api.config.SsoLoginCredentials;
31+
import com.darksci.pardot.api.config.SsoRefreshTokenCredentials;
2532
import com.darksci.pardot.api.rest.interceptor.NoopRequestInterceptor;
2633
import com.darksci.pardot.api.rest.interceptor.RequestInterceptor;
2734

2835
import java.util.Objects;
2936

30-
import static com.darksci.pardot.api.config.LoginType.SSO;
31-
import static com.darksci.pardot.api.config.LoginType.USERNAME_PASSWORD;
32-
3337
/**
3438
* Pardot API Client Configuration Builder.
3539
* Used to construct {@link Configuration} instances.
3640
*/
3741
public class ConfigurationBuilder {
38-
private LoginType loginType;
39-
40-
// Configuration properties for username password login
41-
private String email;
42-
private String password;
43-
private String userKey;
44-
45-
// Configuration properties for SSO login.
46-
private String ssoClientId;
47-
private String ssoClientSecret;
48-
private String businessUnitId;
42+
// Authentication handler
43+
private SessionRefreshHandler sessionRefreshHandler = null;
4944

5045
// Optional Proxy Configuration
5146
private String proxyHost = null;
@@ -77,16 +72,13 @@ public class ConfigurationBuilder {
7772
* Salesforce SSO Authentication: {@link ConfigurationBuilder#withSsoLogin}
7873
*/
7974
public ConfigurationBuilder withUsernameAndPasswordLogin(final String username, final String password, final String userKey) {
80-
this.loginType = USERNAME_PASSWORD;
81-
this.email = Objects.requireNonNull(username);
82-
this.password = Objects.requireNonNull(password);
83-
this.userKey = Objects.requireNonNull(userKey);
84-
85-
return this;
75+
return withCustomAuthenticationHandler(new PasswordSessionRefreshHandler(
76+
new PasswordLoginCredentials(Objects.requireNonNull(username), Objects.requireNonNull(password), Objects.requireNonNull(userKey))
77+
));
8678
}
8779

8880
/**
89-
* For configuring authenticating to the Pardot API using legacy Username, Password, and UserKey values.
81+
* For configuring authenticating to the Pardot API using the password OAuth2 authentication flow.
9082
*
9183
* @param username Salesforce username.
9284
* @param password Salesforce user's password.
@@ -96,12 +88,104 @@ public ConfigurationBuilder withUsernameAndPasswordLogin(final String username,
9688
* @return Builder instance.
9789
*/
9890
public ConfigurationBuilder withSsoLogin(final String username, final String password, final String clientId, final String clientSecret, final String businessUnitId) {
99-
this.loginType = SSO;
100-
this.email = Objects.requireNonNull(username);
101-
this.password = Objects.requireNonNull(password);
102-
this.ssoClientId = Objects.requireNonNull(clientId);
103-
this.ssoClientSecret = Objects.requireNonNull(clientSecret);
104-
this.businessUnitId = Objects.requireNonNull(businessUnitId);
91+
return withCustomAuthenticationHandler(new SsoSessionRefreshHandler(new SsoLoginCredentials(
92+
Objects.requireNonNull(username),
93+
Objects.requireNonNull(password),
94+
Objects.requireNonNull(clientId),
95+
Objects.requireNonNull(clientSecret),
96+
Objects.requireNonNull(businessUnitId)
97+
), AuthorizationServer.DEFAULT_SALESFORCE));
98+
}
99+
100+
/**
101+
* For configuring authenticating to the Pardot API using the password OAuth2 authentication flow.
102+
*
103+
* @param username Salesforce username.
104+
* @param password Salesforce user's password.
105+
* @param clientId Connected Application client or consumer Id.
106+
* @param clientSecret Connected Application client or consumer secret.
107+
* @param businessUnitId Id of the Pardot business unit to connect to.
108+
* @param authorizationServer Override the authorization server address.
109+
* @return Builder instance.
110+
*/
111+
public ConfigurationBuilder withSsoLogin(final String username, final String password, final String clientId, final String clientSecret, final String businessUnitId, final AuthorizationServer authorizationServer) {
112+
return withCustomAuthenticationHandler(new SsoSessionRefreshHandler(new SsoLoginCredentials(
113+
Objects.requireNonNull(username),
114+
Objects.requireNonNull(password),
115+
Objects.requireNonNull(clientId),
116+
Objects.requireNonNull(clientSecret),
117+
Objects.requireNonNull(businessUnitId)
118+
), authorizationServer));
119+
}
120+
121+
/**
122+
* For configuring authenticating to the Pardot API using a previously acquired refresh_token acquired using
123+
* the access_code OAuth2 authentication flow.
124+
*
125+
* @param refreshToken Salesforce refresh_token.
126+
* @param clientId Connected Application client or consumer Id.
127+
* @param clientSecret Connected Application client or consumer secret.
128+
* @param businessUnitId Id of the Pardot business unit to connect to.
129+
* @return Builder instance.
130+
*/
131+
public ConfigurationBuilder withSsoRefreshTokenLogin(final String refreshToken, final String clientId, final String clientSecret, final String businessUnitId) {
132+
return withCustomAuthenticationHandler(new SsoRefreshTokenSessionRefreshHandler(new SsoRefreshTokenCredentials(
133+
Objects.requireNonNull(refreshToken),
134+
Objects.requireNonNull(clientId),
135+
Objects.requireNonNull(clientSecret),
136+
Objects.requireNonNull(businessUnitId)
137+
), AuthorizationServer.DEFAULT_SALESFORCE));
138+
}
139+
140+
/**
141+
* For configuring authenticating to the Pardot API using a refresh_token acquired using
142+
* the access_code oauth2 authentication flow.
143+
*
144+
* @param refreshToken Salesforce refresh_token.
145+
* @param clientId Connected Application client or consumer Id.
146+
* @param clientSecret Connected Application client or consumer secret.
147+
* @param businessUnitId Id of the Pardot business unit to connect to.
148+
* @param authorizationServer Override the authorization server address.
149+
* @return Builder instance.
150+
*/
151+
public ConfigurationBuilder withSsoRefreshTokenLogin(final String refreshToken, final String clientId, final String clientSecret, final String businessUnitId, final AuthorizationServer authorizationServer) {
152+
return withCustomAuthenticationHandler(new SsoRefreshTokenSessionRefreshHandler(new SsoRefreshTokenCredentials(
153+
Objects.requireNonNull(refreshToken),
154+
Objects.requireNonNull(clientId),
155+
Objects.requireNonNull(clientSecret),
156+
Objects.requireNonNull(businessUnitId)
157+
), authorizationServer));
158+
}
159+
160+
/**
161+
* For configuring authenticating to the Pardot API using a previously acquired access_token acquired using
162+
* the access_code OAuth2 authentication flow.
163+
*
164+
* Note this authentication scheme has no provisions for renewing expired sessions automatically.
165+
* See withSsoRefreshTokenLogin() method using a refresh_token.
166+
*
167+
* @param accessToken Salesforce access_token.
168+
* @param clientId Connected Application client or consumer Id.
169+
* @param clientSecret Connected Application client or consumer secret.
170+
* @param businessUnitId Id of the Pardot business unit to connect to.
171+
* @return Builder instance.
172+
*/
173+
public ConfigurationBuilder withSsoAccessTokenLogin(final String accessToken, final String clientId, final String clientSecret, final String businessUnitId) {
174+
return withCustomAuthenticationHandler(new SsoAccessTokenSessionRefreshHandler(new SsoAccessTokenCredentials(
175+
Objects.requireNonNull(accessToken),
176+
Objects.requireNonNull(clientId),
177+
Objects.requireNonNull(clientSecret),
178+
Objects.requireNonNull(businessUnitId)
179+
)));
180+
}
181+
182+
/**
183+
* Allows for injecting a custom {@link SessionRefreshHandler} implementation.
184+
* @param sessionRefreshHandler Interface for handling authentication to Pardot API.
185+
* @return Builder instance.
186+
*/
187+
public ConfigurationBuilder withCustomAuthenticationHandler(final SessionRefreshHandler sessionRefreshHandler) {
188+
this.sessionRefreshHandler = Objects.requireNonNull(sessionRefreshHandler);
105189
return this;
106190
}
107191

@@ -266,25 +350,10 @@ public Configuration build() {
266350
proxyPassword
267351
);
268352
}
269-
PasswordLoginCredentials passwordLoginCredentials = null;
270-
SsoLoginCredentials ssoLoginCredentials = null;
271-
272-
switch (loginType) {
273-
case SSO:
274-
ssoLoginCredentials = new SsoLoginCredentials(email, password, ssoClientId, ssoClientSecret, businessUnitId);
275-
break;
276-
case USERNAME_PASSWORD:
277-
passwordLoginCredentials = new PasswordLoginCredentials(email, password, userKey);
278-
break;
279-
default:
280-
throw new IllegalStateException("Undefined Login type!");
281-
}
282353

283354
// Create instance.
284355
return new Configuration(
285-
loginType,
286-
ssoLoginCredentials,
287-
passwordLoginCredentials,
356+
sessionRefreshHandler,
288357
proxyConfiguration,
289358
pardotApiHost,
290359
pardotApiVersion,

src/main/java/com/darksci/pardot/api/Example.java

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package com.darksci.pardot.api;
1919

20+
import com.darksci.pardot.api.auth.AuthorizationServer;
2021
import com.darksci.pardot.api.config.Configuration;
2122
import com.darksci.pardot.api.request.DateParameter;
2223
import com.darksci.pardot.api.request.account.AccountReadRequest;
@@ -30,7 +31,7 @@
3031
public class Example {
3132

3233
/**
33-
* Example code using Salesforce SSO authetication.
34+
* Example code using Salesforce SSO authentication.
3435
* This method of authenticating to the Pardot API is set to replace the old
3536
* Pardot Username and Password method of authentication and should be used moving forward.
3637
*/
@@ -90,6 +91,103 @@ public static void example_salesforceSsoAuthentication() {
9091
client.close();
9192
}
9293

94+
/**
95+
* Example code using Salesforce SSO authentication with a previously acquired refresh_token.
96+
*/
97+
public static void example_salesforceSsoRefreshTokenAuthentication() {
98+
/*
99+
* Create a new configuration object with your Pardot credentials.
100+
*
101+
* This configuration also allows you to define some optional details on your connection,
102+
* such as using an outbound proxy (authenticated or not).
103+
*/
104+
final ConfigurationBuilder configuration = Configuration.newBuilder()
105+
.withSsoRefreshTokenLogin(
106+
"YourPreviouslyAcquiredRefreshToken",
107+
"YourConnectedAppClientId",
108+
"YourConnectedAppClientSecret",
109+
"YourPardotBusinessUnitId"
110+
);
111+
112+
/*
113+
* Optionally you can explicitly select which API version to use. If none is explicitly selected
114+
* the library will default to version 3, but the library will automatically upgrade to version
115+
* 4 if required to do so.
116+
*/
117+
configuration.withApiVersion3();
118+
119+
/* Or */
120+
configuration.withApiVersion4();
121+
122+
/*
123+
* Create an instance of PardotClient, passing your configuration.
124+
*/
125+
final PardotClient client = new PardotClient(configuration);
126+
127+
/*
128+
* The client will automatically authenticate when you make your first request, no need to
129+
* explicitly login.
130+
*
131+
* Lets create a simple Account request, and execute it.
132+
*/
133+
final AccountReadRequest accountReadRequest = new AccountReadRequest();
134+
final Account account = client.accountRead(accountReadRequest);
135+
136+
/*
137+
* Or lets do a more complex Campaign search.
138+
*/
139+
final CampaignQueryRequest campaignQueryRequest = new CampaignQueryRequest()
140+
.withUpdatedAfter(DateParameter.last7Days())
141+
.withIdLessThan(1234L)
142+
.withSortById()
143+
.withSortOrderDescending();
144+
final CampaignQueryResponse.Result campaignQueryResponse = client.campaignQuery(campaignQueryRequest);
145+
146+
/*
147+
* And when you're done, call close on PardotClient.
148+
*/
149+
client.close();
150+
}
151+
152+
/**
153+
* Example code using Salesforce SSO authentication against a sandbox/test org.
154+
*/
155+
public static void example_salesforceSso_sandboxAuthorizationOrg() {
156+
157+
/**
158+
* Create builder.
159+
*/
160+
final ConfigurationBuilder configuration = Configuration.newBuilder();
161+
162+
/**
163+
* You can pass an optional {@link AuthorizationServer} parameter to the SSO Authentication
164+
* configuration methods.
165+
*
166+
* You can create your own instance by calling new AuthorizationServer("http://your.host.name.here", "/uri/here")
167+
* OR
168+
* You can use one of the ready made instances:
169+
* - AuthorizationServer.DEFAULT_SALESFORCE (Used to authenticate against Production Orgs)
170+
* - AuthorizationServer.SANDBOX_SALESFORCE (Used to authenticate against Sandbox Instances)
171+
*/
172+
configuration.withSsoLogin(
173+
"YourSalesforceUsername",
174+
"YourSalesforcePassword",
175+
"YourConnectedAppClientId",
176+
"YourConnectedAppClientSecret",
177+
"YourPardotBusinessUnitId",
178+
AuthorizationServer.SANDBOX_SALESFORCE
179+
);
180+
181+
// SSO RefreshToken Login.
182+
configuration.withSsoRefreshTokenLogin(
183+
"YourPreviouslyAcquiredRefreshToken",
184+
"YourConnectedAppClientId",
185+
"YourConnectedAppClientSecret",
186+
"YourPardotBusinessUnitId",
187+
AuthorizationServer.SANDBOX_SALESFORCE
188+
);
189+
}
190+
93191
/**
94192
* Example code using Pardot Username and Password Authentication.
95193
* This method of authenticating to the Pardot API to be removed around

0 commit comments

Comments
 (0)