Skip to content

Commit

Permalink
Merge pull request #331 from oneblink/ON-42397
Browse files Browse the repository at this point in the history
ON-42397 # Removed userToken from signed urls to submit forms
  • Loading branch information
Zaxist authored Aug 2, 2024
2 parents 66385ea + 7c2e04b commit 92ffa79
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 58 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@

- Minimum Role Permission to Client docs

### Removed

- **[BREAKING]** `EncryptUserToken` and `DecryptUserToken` methods from the `FormsClient` class
- **[BREAKING]** `secret` property from `FormUrlOptions` class

### Changed

- `GenerateFormUrl` method in the `FormsClient` class to include the `username` property into the JWT payload as the `sub` claim

## [6.2.2] - 2024-07-10

### Changed
Expand Down
3 changes: 0 additions & 3 deletions OneBlink.SDK.Tests/FormsClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -335,15 +335,12 @@ public async void can_generate_form_url()
new FormUrlOptions(
formId: 475,
username: "zac@oneblink.io",
secret: "secret",
preFillData: preFill,
externalId: "myExternalId"

)
);
Assert.Contains("?access_key=", result.formUrl);
Assert.Contains("&externalId=myExternalId", result.formUrl);
Assert.Contains("&userToken=", result.formUrl);
Assert.Contains("&preFillFormDataId=", result.formUrl);
Assert.NotNull(result.expiry);

Expand Down
39 changes: 8 additions & 31 deletions OneBlink.SDK/FormsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,25 +152,6 @@ public async Task Delete(long id, bool overrideLock = false)
await this.oneBlinkApiClient.DeleteRequest(url);
}

public static string EncryptUserToken(string username, string secret)
{
if (String.IsNullOrEmpty(username) || String.IsNullOrEmpty(secret))
{
throw new Exception("Must pass a valid username and secret");
}
AesUserToken aesUserToken = new AesUserToken(secret);
return aesUserToken.encrypt(username);
}
public static string DecryptUserToken(string userToken, string secret)
{
if (String.IsNullOrEmpty(userToken) || String.IsNullOrEmpty(secret))
{
throw new Exception("Must pass a valid userToken and secret");
}
AesUserToken aesUserToken = new AesUserToken(secret);
return aesUserToken.decrypt(userToken);
}

public async Task<FormUrlResult> GenerateFormUrl(FormUrlOptions parameters)
{
if (parameters == null)
Expand Down Expand Up @@ -225,24 +206,22 @@ public async Task<FormUrlResult> GenerateFormUrl(FormUrlOptions parameters)
};
}

string userToken = null;
if (parameters.username != null)
{
AesUserToken aesUserToken = new AesUserToken(parameters.secret);
userToken = aesUserToken.encrypt(parameters.username);
}

// Default expiry for token is 8 hours
int jwtExpiry = parameters.expiryInSeconds ?? 28800;
string token = Token.GenerateJSONWebToken(accessKey: oneBlinkApiClient.accessKey, oneBlinkApiClient.secretKey, jwtExpiry, developerKeyAccess);
string token = Token.GenerateJSONWebToken(
this.oneBlinkApiClient.accessKey,
this.oneBlinkApiClient.secretKey,
jwtExpiry,
developerKeyAccess,
parameters.username
);

string formUrl = _generateFormUrl(
string formUrl = this._generateFormUrl(
formId: parameters.formId,
formsApp: formsApp,
token: token,
externalId: parameters.externalId,
preFillFormDataId: preFillFormDataId,
userToken: userToken,
previousFormSubmissionApprovalId: parameters.previousFormSubmissionApprovalId
);
string expiry = DateTime.UtcNow.AddSeconds(jwtExpiry).ToString("o");
Expand Down Expand Up @@ -422,14 +401,12 @@ private string _generateFormUrl(
string token,
string externalId,
Guid? preFillFormDataId,
string userToken,
long? previousFormSubmissionApprovalId)
{
var query = HttpUtility.ParseQueryString(string.Empty);
OneBlinkHttpClient.AddItemToQuery(query, "access_key", token);
OneBlinkHttpClient.AddItemToQuery(query, nameof(externalId), externalId);
OneBlinkHttpClient.AddItemToQuery(query, nameof(preFillFormDataId), preFillFormDataId);
OneBlinkHttpClient.AddItemToQuery(query, nameof(userToken), userToken);
OneBlinkHttpClient.AddItemToQuery(query, nameof(previousFormSubmissionApprovalId), previousFormSubmissionApprovalId);

string url = $"https://{formsApp.hostname}/forms/{formId}?{query.ToString()}";
Expand Down
30 changes: 21 additions & 9 deletions OneBlink.SDK/Token.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,38 @@
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Security.Claims;

namespace OneBlink.SDK
{
internal class Token
{
internal static string GenerateJSONWebToken(string accessKey, string secretKey, int expiryInSeconds, DeveloperKeyAccess developerKeyAccess = null)
internal static string GenerateJSONWebToken(string accessKey, string secretKey, int expiryInSeconds, DeveloperKeyAccess developerKeyAccess = null, string username = null)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
SymmetricSecurityKey securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
SigningCredentials credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
JwtHeader jwtHeader = new JwtHeader(credentials);

JwtSecurityToken token = new JwtSecurityToken(accessKey,
accessKey,
null,
JwtPayload jwtPayload = new JwtPayload(
issuer: accessKey,
audience: null,
claims: null,
notBefore: null,
expires: DateTime.Now.AddSeconds(expiryInSeconds),
signingCredentials: credentials);

issuedAt: DateTime.Now
);
if (!string.IsNullOrEmpty(username))
{
jwtPayload.Add("sub", username);
}
if (developerKeyAccess != null)
{
token.Payload.Add("oneblink:access", developerKeyAccess);
jwtPayload.Add("oneblink:access", developerKeyAccess);
}

JwtSecurityToken token = new JwtSecurityToken(jwtHeader, jwtPayload);

return new JwtSecurityTokenHandler().WriteToken(token);
}

Expand Down
51 changes: 36 additions & 15 deletions OneBlink.SDK/models/FormUrl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,34 @@ namespace OneBlink.SDK.Model
{
public class FormUrlOptions
{
public long formId { get; }
public long? formsAppId { get; set; }
public int? expiryInSeconds { get; }
public string externalId { get; }
public dynamic preFillData { get; }
public string username { get; }
public string secret { get; }
public long? previousFormSubmissionApprovalId {get;}
public long formId
{
get;
}
public long? formsAppId
{
get; set;
}
public int? expiryInSeconds
{
get;
}
public string externalId
{
get;
}
public dynamic preFillData
{
get;
}
public string username
{
get;
}
public long? previousFormSubmissionApprovalId
{
get;
}

public FormUrlOptions(
long formId,
Expand All @@ -20,29 +40,30 @@ public FormUrlOptions(
string externalId = null,
dynamic preFillData = null,
string username = null,
string secret = null,
long? previousFormSubmissionApprovalId = null
)
{
if (!string.IsNullOrEmpty(username) && string.IsNullOrEmpty(secret)) {
throw new Exception("Must supply \"secret\" as a string if \"username\" is used");
}
this.formId = formId;
this.formsAppId = formsAppId;
this.expiryInSeconds = expiryInSeconds;
this.externalId = externalId;
this.preFillData = preFillData;
this.username = username;
this.secret = secret;
this.previousFormSubmissionApprovalId = previousFormSubmissionApprovalId;
}

}

public class FormUrlResult
{
public string formUrl { get; set; }
public string expiry { get; set; }
public string formUrl
{
get; set;
}
public string expiry
{
get; set;
}

}
}

0 comments on commit 92ffa79

Please sign in to comment.