Skip to content

Commit b0bb853

Browse files
Merge pull request #331 from TransactionProcessing/task/#10_userwelcomeemail
Welcome email added
2 parents a256881 + e56f3c1 commit b0bb853

17 files changed

Lines changed: 227 additions & 106 deletions

File tree

SecurityService.BusinessLogic/ISecurityServiceManager.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ namespace SecurityService.BusinessLogic
1111

1212
public interface ISecurityServiceManager
1313
{
14+
Task SendWelcomeEmail(String userName, CancellationToken cancellationToken);
15+
1416
Task<Boolean> ConfirmEmailAddress(String userName,
1517
String confirmEmailToken,
1618
CancellationToken cancellationToken);
@@ -160,7 +162,6 @@ Task<Guid> CreateUser(String givenName,
160162
String phoneNumber,
161163
Dictionary<String, String> claims,
162164
List<String> roles,
163-
Boolean? requireRegistrationEmail,
164165
CancellationToken cancellationToken);
165166

166167
/// <summary>

SecurityService.BusinessLogic/SecurityServiceManager.cs

Lines changed: 94 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,6 @@ public async Task<Guid> CreateUser(String givenName,
313313
String phoneNumber,
314314
Dictionary<String, String> claims,
315315
List<String> roles,
316-
Boolean? requireRegistrationEmail,
317316
CancellationToken cancellationToken) {
318317
Guid userId = Guid.NewGuid();
319318

@@ -328,11 +327,11 @@ public async Task<Guid> CreateUser(String givenName,
328327
PhoneNumber = phoneNumber
329328
};
330329

331-
// Set the password
332-
// TODO: generate password when not supplied (use GenerateRandomPassword)
330+
String passwordValue = String.IsNullOrEmpty(password) ? SecurityServiceManager.GenerateRandomPassword(this.UserManager.Options.Password) : password;
333331

334-
// Hash the new password
335-
newIdentityUser.PasswordHash = this.PasswordHasher.HashPassword(newIdentityUser, password);
332+
// Hash the default password
333+
newIdentityUser.PasswordHash =
334+
this.PasswordHasher.HashPassword(newIdentityUser, passwordValue);
336335

337336
if (String.IsNullOrEmpty(newIdentityUser.PasswordHash)) {
338337
throw new IdentityResultException("Error generating password hash value, hash was null or empty", IdentityResult.Failed());
@@ -706,7 +705,7 @@ public async Task ProcessPasswordResetRequest(String username,
706705
resetToken = UrlEncoder.Default.Encode(resetToken);
707706
String baseAddress = ConfigurationReader.GetValue("ServiceOptions", "PublicOrigin");
708707
String uri = $"{baseAddress}/Account/ForgotPassword/Confirm?userName={user.UserName}&resetToken={resetToken}&clientId={clientId}";
709-
708+
710709
TokenResponse token = await this.GetToken(cancellationToken);
711710
SendEmailRequest emailRequest = this.BuildPasswordResetEmailRequest(user, uri);
712711
try {
@@ -717,6 +716,24 @@ public async Task ProcessPasswordResetRequest(String username,
717716
}
718717
}
719718

719+
public async Task SendWelcomeEmail(String userName,
720+
CancellationToken cancellationToken) {
721+
IdentityUser i = await this.UserManager.FindByNameAsync(userName);
722+
await this.UserManager.RemovePasswordAsync(i);
723+
String generatedPassword = SecurityServiceManager.GenerateRandomPassword(this.UserManager.Options.Password);
724+
await this.UserManager.AddPasswordAsync(i, generatedPassword);
725+
726+
// Send Email
727+
TokenResponse token = await this.GetToken(cancellationToken);
728+
SendEmailRequest emailRequest = this.BuildWelcomeEmail(i.Email, generatedPassword);
729+
try {
730+
await this.MessagingServiceClient.SendEmail(token.AccessToken, emailRequest, cancellationToken);
731+
}
732+
catch(Exception ex) {
733+
Logger.LogError(ex);
734+
}
735+
}
736+
720737
[ExcludeFromCodeCoverage]
721738
public async Task Signout() {
722739
await this.SignInManager.SignOutAsync();
@@ -791,6 +808,36 @@ private SendEmailRequest BuildPasswordResetEmailRequest(IdentityUser user,
791808
return request;
792809
}
793810

811+
private SendEmailRequest BuildWelcomeEmail(String emailAddress,
812+
String password) {
813+
StringBuilder mesasgeBuilder = new StringBuilder();
814+
mesasgeBuilder.AppendLine("<html><body>");
815+
mesasgeBuilder.AppendLine("<p>Welcome to Transaction Processing System</p>");
816+
mesasgeBuilder.AppendLine("<p></p>");
817+
mesasgeBuilder.AppendLine("<p>Please find below your user details:</p>");
818+
mesasgeBuilder.AppendLine("<table>");
819+
mesasgeBuilder.AppendLine("<tr><td><strong>User Name</strong></td></tr>");
820+
mesasgeBuilder.AppendLine($"<tr><td id=\"username\">{emailAddress}</td></tr>");
821+
mesasgeBuilder.AppendLine("<tr><td><strong>Password</strong></td></tr>");
822+
mesasgeBuilder.AppendLine($"<tr><td id=\"password\">{password}</td></tr>");
823+
mesasgeBuilder.AppendLine("</table>");
824+
mesasgeBuilder.AppendLine("</body></html>");
825+
826+
SendEmailRequest request = new() {
827+
Body = mesasgeBuilder.ToString(),
828+
ConnectionIdentifier = Guid.NewGuid(),
829+
FromAddress = "golfhandicapping@btinternet.com",
830+
IsHtml = true,
831+
Subject = "Welcome to Transaction Processing",
832+
ToAddresses = new List<String> {
833+
emailAddress,
834+
"stuart_ferguson1@outlook.com"
835+
}
836+
};
837+
838+
return request;
839+
}
840+
794841
/// <summary>
795842
/// Converts the users claims.
796843
/// </summary>
@@ -816,6 +863,47 @@ private async Task<List<String>> ConvertUsersRoles(IdentityUser identityUser) {
816863
return roles.ToList();
817864
}
818865

866+
private static String GenerateRandomPassword(PasswordOptions opts = null) {
867+
if (opts == null)
868+
opts = new PasswordOptions {
869+
RequiredLength = 8,
870+
RequiredUniqueChars = 4,
871+
RequireDigit = true,
872+
RequireLowercase = true,
873+
RequireNonAlphanumeric = true,
874+
RequireUppercase = true
875+
};
876+
877+
String[] randomChars = {
878+
"ABCDEFGHJKLMNOPQRSTUVWXYZ", // uppercase
879+
"abcdefghijkmnopqrstuvwxyz", // lowercase
880+
"0123456789", // digits
881+
"!@$?_-" // non-alphanumeric
882+
};
883+
884+
Random rand = new Random(Environment.TickCount);
885+
List<Char> chars = new List<Char>();
886+
887+
if (opts.RequireUppercase)
888+
chars.Insert(rand.Next(0, chars.Count), randomChars[0][rand.Next(0, randomChars[0].Length)]);
889+
890+
if (opts.RequireLowercase)
891+
chars.Insert(rand.Next(0, chars.Count), randomChars[1][rand.Next(0, randomChars[1].Length)]);
892+
893+
if (opts.RequireDigit)
894+
chars.Insert(rand.Next(0, chars.Count), randomChars[2][rand.Next(0, randomChars[2].Length)]);
895+
896+
if (opts.RequireNonAlphanumeric)
897+
chars.Insert(rand.Next(0, chars.Count), randomChars[3][rand.Next(0, randomChars[3].Length)]);
898+
899+
for (Int32 i = chars.Count; i < opts.RequiredLength || chars.Distinct().Count() < opts.RequiredUniqueChars; i++) {
900+
String rcs = randomChars[rand.Next(0, randomChars.Length)];
901+
chars.Insert(rand.Next(0, chars.Count), rcs[rand.Next(0, rcs.Length)]);
902+
}
903+
904+
return new String(chars.ToArray());
905+
}
906+
819907
private async Task<TokenResponse> GetToken(CancellationToken cancellationToken) {
820908
// Get a token to talk to the estate service
821909
String clientId = ConfigurationReader.GetValue("AppSettings", "ClientId");

SecurityService.DataTransferObjects/Requests/CreateUserRequest.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ public class CreateUserRequest
1515
[JsonProperty("phone_number")]
1616
public String PhoneNumber { get; set; }
1717

18-
[JsonProperty("password")]
19-
public String Password { get; set; }
20-
2118
[JsonProperty("claims")]
2219
public Dictionary<String, String> Claims { get; set; }
2320

@@ -33,7 +30,7 @@ public class CreateUserRequest
3330
[JsonProperty("family_name")]
3431
public String FamilyName { get; set; }
3532

36-
[JsonProperty("require_registration_email")]
37-
public Boolean? RequireRegistrationEmail { get; set; }
33+
[JsonProperty("password")]
34+
public String Password { get; set; }
3835
}
3936
}

SecurityService.IntegrationTests/Users/Users.feature

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,25 @@ Background:
1010

1111
Scenario: Create User
1212
Given I create the following users
13-
| Email Address | Password | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |
14-
| testuser1@testing.co.uk | 123456 | 123456789 | Test | | User 1 | Claim1:value1,Claim2:value2 | TestRole1 |
13+
| Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |
14+
| testuser1@testing.co.uk | 123456789 | Test | | User 1 | Claim1:value1,Claim2:value2 | TestRole1 |
1515

1616
Scenario: Get User
1717
Given I create the following users
18-
| Email Address | Password | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |
19-
| testuser1@testing.co.uk | 123456 | 123456789 | Test | | User 1 | | TestRole1 |
20-
| testuser2@testing.co.uk | 123456 | 123456789 | Test | | User 2 | | TestRole2 |
18+
| Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |
19+
| testuser1@testing.co.uk | 123456789 | Test | | User 1 | | TestRole1 |
20+
| testuser2@testing.co.uk | 123456789 | Test | | User 2 | | TestRole2 |
2121
When I get the user with user name 'testuser1@testing.co.uk' the user details are returned as follows
2222
| Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |
2323
| testuser1@testing.co.uk | 123456789 | Test | | User 1 | email:testuser1@testing.co.uk, given_name:Test, family_name:User 1 | TestRole1 |
2424

2525
@PRTest
2626
Scenario: Get Users
2727
Given I create the following users
28-
| Email Address | Password | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |
29-
| testuser1@testing.co.uk | 123456 | 123456789 | Test | | User 1 | | TestRole1 |
30-
| testuser2@testing.co.uk | 123456 | 123456789 | Test | | User 2 | | TestRole2 |
31-
| testuser3@testing.co.uk | 123456 | 123456789 | Test | | User 3 | | TestRole3 |
28+
| Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |
29+
| testuser1@testing.co.uk | 123456789 | Test | | User 1 | | TestRole1 |
30+
| testuser2@testing.co.uk | 123456789 | Test | | User 2 | | TestRole2 |
31+
| testuser3@testing.co.uk | 123456789 | Test | | User 3 | | TestRole3 |
3232
When I get the users 3 users details are returned as follows
3333
| Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |
3434
| testuser1@testing.co.uk | 123456789 | Test | | User 1 | email:testuser1@testing.co.uk, given_name:Test, family_name:User 1 | TestRole1 |

SecurityService.IntegrationTests/Users/Users.feature.cs

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

SecurityService.IntegrationTests/Users/UsersSteps.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@ public async Task GivenICreateTheFollowingUsers(Table table)
8080
MiddleName = SpecflowTableHelper.GetStringRowValue(tableRow, "Middle name"),
8181
Claims = userClaims,
8282
Roles = string.IsNullOrEmpty(roles) ? null : roles.Split(",").ToList(),
83-
Password = SpecflowTableHelper.GetStringRowValue(tableRow, "Password")
84-
};
83+
Password= SpecflowTableHelper.GetStringRowValue(tableRow, "Password")
84+
};
85+
8586
CreateUserResponse createUserResponse = await this.CreateUser(createUserRequest, CancellationToken.None).ConfigureAwait(false);
8687

8788
createUserResponse.ShouldNotBeNull();

SecurityService.OpenIdConnect.IntegrationTests/ChangePassword/ChangePassword.feature

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,20 @@ Background:
2121
| ClientId | Name | Secret | Scopes | GrantTypes | RedirectUris | PostLogoutRedirectUris | RequireConsent | AllowOfflineAccess | ClientUri |
2222
| estateUIClient | Merchant Client | Secret1 | estateManagement,openid,email,profile | hybrid | https://[url]:[port]/signin-oidc | https://[url]:[port]/signout-oidc | false | true | https://[url]:[port] |
2323

24-
Given I create the following users
25-
| Email Address | Password | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |
26-
| estateuser@testestate1.co.uk | 123456 | 123456789 | Test | | User 1 | EstateId:1 | Estate |
2724

2825
@PRTest
2926
Scenario: Change Passwword
27+
Given I create the following users
28+
| Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |
29+
| estateuser@testestate1.co.uk | 123456789 | Test | | User 1 | EstateId:1 | Estate |
30+
Then I get an email with a confirm email address link
31+
When I navigate to the confirm email address
32+
Then I am presented with the confirm email address successful screen
33+
And I get a welcome email with my login details
3034
Given I am on the application home page
3135
When I click the 'Privacy' link
3236
Then I am presented with a login screen
33-
When I login with the username 'estateuser@testestate1.co.uk' and password '123456'
37+
When I login with the username 'estateuser@testestate1.co.uk' and the provided password
3438
Then I am presented with the privacy screen
3539
When I click the 'ChangePassword' link
3640
Then I am presented with a change password screen

0 commit comments

Comments
 (0)