Skip to content

Commit 80d12b5

Browse files
committed
added modification to support PKCE authorization in Quick ACG
1 parent e8ec920 commit 80d12b5

File tree

8 files changed

+62
-58
lines changed

8 files changed

+62
-58
lines changed

Quick_ACG/pom.xml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
<includes>
159159
<include>Locals.java</include>
160160
<include>User.java</include>
161+
<include>EnvelopeDocumentInfo.java</include>
161162
</includes>
162163
</resource>
163164
<resource>
@@ -199,7 +200,16 @@
199200
<targetPath>${basedir}/src/main/java/com/docusign/core/security</targetPath>
200201
<directory>../src/main/java/com/docusign/core/security</directory>
201202
<includes>
202-
<include>OAuthProperties.java</include>
203+
<include>SecurityHelpers.java</include>
204+
<include>JWTOAuth2User.java</include>
205+
<include>CustomAuthenticationFailureHandler.java</include>
206+
</includes>
207+
</resource>
208+
<resource>
209+
<targetPath>${basedir}/src/main/java/com/docusign/core/security/acg</targetPath>
210+
<directory>../src/main/java/com/docusign/core/security/acg</directory>
211+
<includes>
212+
<include>ACGAuthenticationMethod.java</include>
203213
</includes>
204214
</resource>
205215
<resource>
Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,33 @@
11
package com.docusign.core.model;
22

3+
import com.docusign.esign.client.auth.OAuth;
34
import lombok.Data;
45
import org.springframework.context.annotation.Scope;
56
import org.springframework.context.annotation.ScopedProxyMode;
67
import org.springframework.stereotype.Component;
78
import org.springframework.web.context.WebApplicationContext;
89

910
import java.io.Serializable;
11+
import java.util.List;
1012
import java.util.UUID;
1113

1214
@Component
13-
@Scope(value = WebApplicationContext.SCOPE_SESSION,
14-
proxyMode = ScopedProxyMode.TARGET_CLASS)
15+
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
1516
@Data
1617
public class Session implements Serializable {
1718
private static final long serialVersionUID = 2695379118371574037L;
1819

20+
public Long tokenExpirationTime;
21+
1922
private String accountId;
23+
2024
private String accountName;
25+
2126
private String basePath;
22-
private String statusCFR;
23-
private String roomsBasePath;
27+
2428
private String envelopeId;
25-
private String templateId;
26-
private String templateName;
27-
private String permissionProfileId;
28-
private String permissionProfileName;
29-
private String apiIndexPath;
30-
private boolean refreshToken = false;
31-
private String clickwrapId;
32-
private String clickwrapVersionNumber;
33-
private String exportId;
34-
private String importId;
35-
private UUID orgId;
36-
public UUID bulkListId;
29+
30+
private String statusCFR;
31+
32+
private Boolean isPKCEWorking = true;
3733
}

src/main/java/com/docusign/DSConfiguration.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ public ManifestStructure getCodeExamplesText() {
168168

169169
try {
170170
codeExamplesText = new ObjectMapper().readValue(loadFileData(codeExamplesManifest),
171-
ManifestStructure.class);
171+
ManifestStructure.class);
172172
} catch (Exception e) {
173173
e.printStackTrace();
174174
}
@@ -182,8 +182,8 @@ public String loadFileData(String linkToManifestFile) throws Exception {
182182
httpConnection.setRequestMethod(HttpMethod.GET);
183183

184184
httpConnection.setRequestProperty(
185-
HttpHeaders.CONTENT_TYPE,
186-
String.valueOf(MediaType.APPLICATION_JSON));
185+
HttpHeaders.CONTENT_TYPE,
186+
String.valueOf(MediaType.APPLICATION_JSON));
187187

188188
int responseCode = httpConnection.getResponseCode();
189189

src/main/java/com/docusign/core/controller/IndexController.java

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public String index(ModelMap model, HttpServletResponse response) throws Excepti
9595
}
9696

9797
if (config.getQuickstart().equals("true") && config.getSelectedApiIndex().equals(ApiIndex.ESIGNATURE) &&
98-
!(SecurityContextHolder.getContext().getAuthentication() instanceof OAuth2AuthenticationToken)) {
98+
!(SecurityContextHolder.getContext().getAuthentication() instanceof OAuth2AuthenticationToken)) {
9999
String site = ApiIndex.ESIGNATURE.getPathOfFirstExample();
100100
response.setStatus(response.SC_MOVED_TEMPORARILY);
101101
response.setHeader(LOCATION_HEADER, site);
@@ -114,7 +114,7 @@ public String index(ModelMap model, HttpServletResponse response) throws Excepti
114114

115115
@GetMapping(path = "/ds/mustAuthenticate")
116116
public ModelAndView mustAuthenticateController(ModelMap model, HttpServletRequest req, HttpServletResponse resp)
117-
throws IOException {
117+
throws IOException {
118118
model.addAttribute(LAUNCHER_TEXTS, config.getCodeExamplesText().SupportingTexts);
119119
model.addAttribute(ATTR_TITLE, config.getCodeExamplesText().SupportingTexts.LoginPage.LoginButton);
120120

@@ -124,11 +124,12 @@ public ModelAndView mustAuthenticateController(ModelMap model, HttpServletReques
124124
config.setIsConsentRedirectActivated(false);
125125
this.session.setAuthTypeSelected(AuthType.JWT);
126126

127-
return new ModelAndView(new JWTAuthenticationMethod().loginUsingJWT(config, session, redirectURL));
127+
return new ModelAndView(
128+
new JWTAuthenticationMethod().loginUsingJWT(config, session, redirectURL, ApiType.getScopeList()));
128129
}
129130

130131
boolean isRedirectToMonitor = redirectURL.toLowerCase().contains("/m") &&
131-
!redirectURL.toLowerCase().contains("/mae");
132+
!redirectURL.toLowerCase().contains("/mae");
132133
if (session.isRefreshToken() || config.getQuickstart().equals("true")) {
133134
config.setQuickstart("false");
134135

@@ -148,12 +149,13 @@ private ModelAndView checkForMonitorRedirects(String redirectURL) {
148149
this.session.setAuthTypeSelected(AuthType.JWT);
149150
redirectURL = redirectURL != "/" ? redirectURL : session.getMonitorExampleRedirect();
150151
this.session.setMonitorExampleRedirect(null);
151-
return new ModelAndView(new JWTAuthenticationMethod().loginUsingJWT(config, session, redirectURL));
152+
return new ModelAndView(
153+
new JWTAuthenticationMethod().loginUsingJWT(config, session, redirectURL, ApiType.getScopeList()));
152154
}
153155

154156
@GetMapping("/pkce")
155157
public RedirectView pkce(String code, String state, HttpServletRequest req, HttpServletResponse resp)
156-
throws Exception {
158+
throws Exception {
157159
String redirectURL = getRedirectURLForJWTAuthentication(req, resp);
158160
RedirectView redirect;
159161
try {
@@ -167,25 +169,25 @@ public RedirectView pkce(String code, String state, HttpServletRequest req, Http
167169
}
168170

169171
@PostMapping("/ds/authenticate")
170-
public RedirectView authenticate(ModelMap model, @RequestBody MultiValueMap <String, String> formParams,
171-
HttpServletRequest req, HttpServletResponse resp) throws Exception {
172+
public RedirectView authenticate(ModelMap model, @RequestBody MultiValueMap<String, String> formParams,
173+
HttpServletRequest req, HttpServletResponse resp) throws Exception {
172174
if (!formParams.containsKey("selectAuthType")) {
173175
model.addAttribute("message", "Select option with selectAuthType name must be provided.");
174176
return new RedirectView("pages/error");
175177
}
176178

177179
String redirectURL = getRedirectURLForJWTAuthentication(req, resp);
178180

179-
List <String> selectAuthTypeObject = formParams.get("selectAuthType");
181+
List<String> selectAuthTypeObject = formParams.get("selectAuthType");
180182
AuthType authTypeSelected = AuthType.valueOf(selectAuthTypeObject.get(0));
181183

182184
if (authTypeSelected.equals(AuthType.JWT)) {
183185
this.session.setAuthTypeSelected(AuthType.JWT);
184-
return new JWTAuthenticationMethod().loginUsingJWT(config, session, redirectURL);
186+
return new JWTAuthenticationMethod().loginUsingJWT(config, session, redirectURL, ApiType.getScopeList());
185187
} else {
186188
this.session.setAuthTypeSelected(AuthType.AGC);
187189
if (this.session.getIsPKCEWorking()) {
188-
return new ACGAuthenticationMethod().initiateAuthorization(config);
190+
return new ACGAuthenticationMethod().initiateAuthorization(config, ApiType.getScopeList());
189191
} else {
190192
return getRedirectView(authTypeSelected);
191193
}
@@ -196,7 +198,7 @@ private String getRedirectURLForJWTAuthentication(HttpServletRequest req, HttpSe
196198
SavedRequest savedRequest = requestCache.getRequest(req, resp);
197199

198200
String[] examplesCodes = new String[] {
199-
ApiIndex.CLICK.getExamplesPathCode(),
201+
ApiIndex.CLICK.getExamplesPathCode(),
200202
ApiIndex.ESIGNATURE.getExamplesPathCode(),
201203
ApiIndex.MONITOR.getExamplesPathCode(),
202204
ApiIndex.ADMIN.getExamplesPathCode(),
@@ -209,7 +211,7 @@ private String getRedirectURLForJWTAuthentication(HttpServletRequest req, HttpSe
209211

210212
if (indexOfExampleCodeInRedirect != -1) {
211213
Boolean hasNumbers = savedRequest.getRedirectUrl().substring(indexOfExampleCodeInRedirect)
212-
.matches(".*\\d.*");
214+
.matches(".*\\d.*");
213215

214216
return "GET".equals(savedRequest.getMethod()) && hasNumbers ? savedRequest.getRedirectUrl() : "/";
215217
}
@@ -220,8 +222,8 @@ private String getRedirectURLForJWTAuthentication(HttpServletRequest req, HttpSe
220222

221223
@GetMapping(path = "/ds-return")
222224
public String returnController(@RequestParam(value = ATTR_STATE, required = false) String state,
223-
@RequestParam(value = ATTR_EVENT, required = false) String event,
224-
@RequestParam(required = false) String envelopeId, ModelMap model) {
225+
@RequestParam(value = ATTR_EVENT, required = false) String event,
226+
@RequestParam(required = false) String envelopeId, ModelMap model) {
225227
model.addAttribute(LAUNCHER_TEXTS, config.getCodeExamplesText().SupportingTexts);
226228
model.addAttribute(ATTR_TITLE, "Return from DocuSign");
227229
model.addAttribute(ATTR_EVENT, event);

src/main/java/com/docusign/core/model/ApiType.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.docusign.core.model;
22

3+
import java.util.ArrayList;
34
import java.util.Arrays;
5+
import java.util.List;
46

57
public enum ApiType {
68
ESIGNATURE("eSignature API", new String[] { "signature" }, "eg"),
@@ -37,6 +39,14 @@ public static ApiType giveTypeByName(String exampleName) {
3739
.get();
3840
}
3941

42+
public static List<String> getScopeList() {
43+
List<String> scopes = new ArrayList<>();
44+
for (ApiType scope : ApiType.values()) {
45+
scopes.addAll(Arrays.asList(scope.getScopes()));
46+
}
47+
return scopes;
48+
}
49+
4050
public String[] getScopes() {
4151
return scopes;
4252
}

src/main/java/com/docusign/core/security/SecurityHelpers.java

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,18 @@
44
import java.security.NoSuchAlgorithmException;
55
import java.io.IOException;
66
import java.nio.charset.StandardCharsets;
7-
import java.util.ArrayList;
8-
import java.util.Arrays;
97
import java.util.Base64;
108
import java.util.List;
119
import java.util.Random;
1210

1311
import org.springframework.security.core.context.SecurityContextHolder;
1412
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
15-
import com.docusign.core.model.ApiType;
1613
import com.docusign.core.model.Session;
1714
import com.docusign.esign.client.auth.OAuth;
1815
import com.fasterxml.jackson.databind.JsonNode;
1916
import com.fasterxml.jackson.databind.ObjectMapper;
2017

2118
public class SecurityHelpers {
22-
public static List<String> getScopeList() {
23-
List<String> scopes = new ArrayList<>();
24-
for (ApiType scope : ApiType.values()) {
25-
scopes.addAll(Arrays.asList(scope.getScopes()));
26-
}
27-
return scopes;
28-
}
29-
3019
public static String generateCodeVerifier() {
3120
byte[] randomBytes = new byte[32];
3221
new Random().nextBytes(randomBytes);
@@ -46,12 +35,12 @@ public static String parseJsonField(String jsonResponse, String field) throws IO
4635
}
4736

4837
public static void setSpringSecurityAuthentication(
49-
List<String> scopes,
50-
String oAuthToken,
51-
OAuth.UserInfo userInfo,
52-
String accountId,
53-
Session session,
54-
String expiresIn) {
38+
List<String> scopes,
39+
String oAuthToken,
40+
OAuth.UserInfo userInfo,
41+
String accountId,
42+
Session session,
43+
String expiresIn) {
5544
JWTOAuth2User principal = new JWTOAuth2User();
5645
principal.setAuthorities(scopes);
5746
principal.setCreated(userInfo.getCreated());

src/main/java/com/docusign/core/security/acg/ACGAuthenticationMethod.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ public class ACGAuthenticationMethod {
2626

2727
private static String codeChallenge;
2828

29-
public RedirectView initiateAuthorization(DSConfiguration configuration) throws Exception {
30-
List<String> scopes = SecurityHelpers.getScopeList();
31-
29+
public RedirectView initiateAuthorization(DSConfiguration configuration, List<String> scopes) throws Exception {
3230
codeVerifier = SecurityHelpers.generateCodeVerifier();
3331
codeChallenge = SecurityHelpers.generateCodeChallenge(codeVerifier);
3432

src/main/java/com/docusign/core/security/jwt/JWTAuthenticationMethod.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ public class JWTAuthenticationMethod {
2929
public RedirectView loginUsingJWT(
3030
DSConfiguration configuration,
3131
Session session,
32-
String redirectURL) {
33-
List<String> scopes = SecurityHelpers.getScopeList();
34-
32+
String redirectURL,
33+
List<String> scopes) {
3534
try {
3635
ApiClient apiClient = new ApiClient(configuration.getBasePath());
3736
byte[] privateKeyBytes = Files.readAllBytes(Paths.get(configuration.getPrivateKeyPath()));

0 commit comments

Comments
 (0)