Skip to content

Commit e435913

Browse files
committedMay 17, 2013
begin idiomatic refactor on IdentityAccess
1 parent 32b3b46 commit e435913

36 files changed

+852
-811
lines changed
 

‎.gitattributes

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
###############################################################################
2+
# Set default behavior to automatically normalize line endings.
3+
###############################################################################
4+
* text=auto
5+
6+
###############################################################################
7+
# Set default behavior for command prompt diff.
8+
#
9+
# This is need for earlier builds of msysgit that does not have it on by
10+
# default for csharp files.
11+
# Note: This is only used by command line
12+
###############################################################################
13+
#*.cs diff=csharp
14+
15+
###############################################################################
16+
# Set the merge driver for project and solution files
17+
#
18+
# Merging from the command prompt will add diff markers to the files if there
19+
# are conflicts (Merging from VS is not affected by the settings below, in VS
20+
# the diff markers are never inserted). Diff markers may cause the following
21+
# file extensions to fail to load in VS. An alternative would be to treat
22+
# these files as binary and thus will always conflict and require user
23+
# intervention with every merge. To do so, just uncomment the entries below
24+
###############################################################################
25+
#*.sln merge=binary
26+
#*.csproj merge=binary
27+
#*.vbproj merge=binary
28+
#*.vcxproj merge=binary
29+
#*.vcproj merge=binary
30+
#*.dbproj merge=binary
31+
#*.fsproj merge=binary
32+
#*.lsproj merge=binary
33+
#*.wixproj merge=binary
34+
#*.modelproj merge=binary
35+
#*.sqlproj merge=binary
36+
#*.wwaproj merge=binary
37+
38+
###############################################################################
39+
# behavior for image files
40+
#
41+
# image files are treated as binary by default.
42+
###############################################################################
43+
#*.jpg binary
44+
#*.png binary
45+
#*.gif binary
46+
47+
###############################################################################
48+
# diff behavior for common document formats
49+
#
50+
# Convert binary document formats to text before diffing them. This feature
51+
# is only available from the command line. Turn it on by uncommenting the
52+
# entries below.
53+
###############################################################################
54+
#*.doc diff=astextplain
55+
#*.DOC diff=astextplain
56+
#*.docx diff=astextplain
57+
#*.DOCX diff=astextplain
58+
#*.dot diff=astextplain
59+
#*.DOT diff=astextplain
60+
#*.pdf diff=astextplain
61+
#*.PDF diff=astextplain
62+
#*.rtf diff=astextplain
63+
#*.RTF diff=astextplain

‎iddd_agilepm/SaaSOvation.AgilePM.Domain.Model.Products/Product.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public Product(
6868

6969
public TenantId TenantId { get; private set; }
7070

71-
private ISet<ProductBacklogItem> BacklogItems { get; set; }
71+
ISet<ProductBacklogItem> BacklogItems { get; set; }
7272

7373
public ICollection<ProductBacklogItem> AllBacklogItems()
7474
{
@@ -122,7 +122,7 @@ public BacklogItems.BacklogItem PlanBacklogItem(
122122
BacklogItemType type,
123123
StoryPoints storyPoints)
124124
{
125-
BacklogItems.BacklogItem backlogItem =
125+
var backlogItem =
126126
new BacklogItems.BacklogItem(
127127
this.TenantId,
128128
this.ProductId,

‎iddd_agilepm/SaaSOvation.AgilePM.Domain.Model.Products/ProductBacklogItem.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ public ProductBacklogItem(
4242

4343
public override bool Equals(object anotherObject)
4444
{
45-
bool equalObjects = false;
45+
var equalObjects = false;
4646

4747
if (anotherObject != null && this.GetType() == anotherObject.GetType())
4848
{
49-
ProductBacklogItem typedObject = (ProductBacklogItem)anotherObject;
49+
var typedObject = (ProductBacklogItem)anotherObject;
5050
equalObjects =
5151
this.TenantId.Equals(typedObject.TenantId) &&
5252
this.ProductId.Equals(typedObject.ProductId) &&

‎iddd_agilepm/SaaSOvation.AgilePM.Domain.Model.Products/ProductBacklogItemPlanned.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace SaaSOvation.AgilePM.Domain.Model.Products
1919
using SaaSOvation.AgilePM.Domain.Model.Products.BacklogItems;
2020
using SaaSOvation.AgilePM.Domain.Model.Tenants;
2121

22-
public class ProductBacklogItemPlanned : DomainEvent
22+
public class ProductBacklogItemPlanned : IDomainEvent
2323
{
2424
public ProductBacklogItemPlanned(
2525
TenantId tenantId,

‎iddd_agilepm/SaaSOvation.AgilePM.Domain.Model.Products/ProductCreated.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace SaaSOvation.AgilePM.Domain.Model.Products
2020
using SaaSOvation.AgilePM.Domain.Model.Tenants;
2121
using SaaSOvation.Common.Domain.Model;
2222

23-
public class ProductCreated : DomainEvent
23+
public class ProductCreated : IDomainEvent
2424
{
2525
public ProductCreated(
2626
TenantId tenantId,

‎iddd_agilepm/SaaSOvation.AgilePM.Domain.Model.Products/ProductDiscussion.cs

+2-9
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,9 @@ public static ProductDiscussion FromAvailability(
2323
DiscussionAvailability availability)
2424
{
2525
if (availability == DiscussionAvailability.Ready)
26-
{
2726
throw new InvalidOperationException("Cannot be created ready.");
28-
}
2927

30-
DiscussionDescriptor descriptor =
31-
new DiscussionDescriptor(DiscussionDescriptor.UNDEFINED_ID);
28+
var descriptor = new DiscussionDescriptor(DiscussionDescriptor.UNDEFINED_ID);
3229

3330
return new ProductDiscussion(descriptor, availability);
3431
}
@@ -53,13 +50,9 @@ public ProductDiscussion(ProductDiscussion productDiscussion)
5350
public ProductDiscussion NowReady(DiscussionDescriptor descriptor)
5451
{
5552
if (descriptor == null || descriptor.IsUndefined())
56-
{
57-
throw new InvalidOperationException("The discussion descriptor must be defined.");
58-
}
53+
throw new ArgumentException("The discussion descriptor must be defined.");
5954
if (this.Availability != DiscussionAvailability.Requested)
60-
{
6155
throw new InvalidOperationException("The discussion must be requested first.");
62-
}
6356

6457
return new ProductDiscussion(descriptor, DiscussionAvailability.Ready);
6558
}

‎iddd_agilepm/SaaSOvation.AgilePM.Domain.Model.Products/ProductDiscussionInitiated.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace SaaSOvation.AgilePM.Domain.Model.Products
1818
using SaaSOvation.Common.Domain.Model;
1919
using System;
2020

21-
public class ProductDiscussionInitiated : DomainEvent
21+
public class ProductDiscussionInitiated : IDomainEvent
2222
{
2323
public ProductDiscussionInitiated(TenantId tenantId, ProductId productId, ProductDiscussion productDiscussion)
2424
{

‎iddd_agilepm/SaaSOvation.AgilePM.Domain.Model.Products/ProductDiscussionRequested.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace SaaSOvation.AgilePM.Domain.Model.Products
1919
using SaaSOvation.AgilePM.Domain.Model.Tenants;
2020
using SaaSOvation.Common.Domain.Model;
2121

22-
public class ProductDiscussionRequested : DomainEvent
22+
public class ProductDiscussionRequested : IDomainEvent
2323
{
2424
public ProductDiscussionRequested(
2525
TenantId tenantId,

‎iddd_agilepm/SaaSOvation.AgilePM.Domain.Model.Products/ProductReleaseScheduled.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace SaaSOvation.AgilePM.Domain.Model.Products
1919
using SaaSOvation.AgilePM.Domain.Model.Products.Releases;
2020
using SaaSOvation.Common.Domain.Model;
2121

22-
public class ProductReleaseScheduled : DomainEvent
22+
public class ProductReleaseScheduled : IDomainEvent
2323
{
2424
public ProductReleaseScheduled(
2525
TenantId tenantId,

‎iddd_agilepm/SaaSOvation.AgilePM.Domain.Model.Products/ProductSprintScheduled.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace SaaSOvation.AgilePM.Domain.Model.Products
2020
using SaaSOvation.Common.Domain.Model;
2121
using SaaSOvation.AgilePM.Domain.Model.Products.Sprints;
2222

23-
public class ProductSprintScheduled : DomainEvent
23+
public class ProductSprintScheduled : IDomainEvent
2424
{
2525
public ProductSprintScheduled(
2626
TenantId tenantId,

‎iddd_common/SaaSOvation.Common.Domain.Model/DomainEventPublisher.cs

+19-20
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,19 @@ public static DomainEventPublisher Instance
3636

3737
private DomainEventPublisher()
3838
{
39-
this.Publishing = false;
39+
this.publishing = false;
4040
}
4141

42-
private bool Publishing { get; set; }
42+
bool publishing;
4343

44-
private List<DomainEventSubscriber<DomainEvent>> _subscribers;
45-
private List<DomainEventSubscriber<DomainEvent>> Subscribers
44+
List<IDomainEventSubscriber<IDomainEvent>> _subscribers;
45+
List<IDomainEventSubscriber<IDomainEvent>> Subscribers
4646
{
4747
get
4848
{
4949
if (this._subscribers == null)
5050
{
51-
this._subscribers = new List<DomainEventSubscriber<DomainEvent>>();
51+
this._subscribers = new List<IDomainEventSubscriber<IDomainEvent>>();
5252
}
5353

5454
return this._subscribers;
@@ -59,58 +59,57 @@ private List<DomainEventSubscriber<DomainEvent>> Subscribers
5959
}
6060
}
6161

62-
public void Publish<T>(T domainEvent) where T : DomainEvent
62+
public void Publish<T>(T domainEvent) where T : IDomainEvent
6363
{
64-
if (!this.Publishing && this.HasSubscribers())
64+
if (!this.publishing && this.HasSubscribers())
6565
{
6666
try
6767
{
68-
this.Publishing = true;
68+
this.publishing = true;
6969

70-
Type eventType = domainEvent.GetType();
70+
var eventType = domainEvent.GetType();
7171

72-
foreach (DomainEventSubscriber<T> subscriber in this.Subscribers)
72+
foreach (var subscriber in this.Subscribers)
7373
{
74-
Type subscribedToType = subscriber.SubscribedToEventType();
75-
76-
if (eventType == subscribedToType || subscribedToType == typeof(DomainEvent))
74+
var subscribedToType = subscriber.SubscribedToEventType();
75+
if (eventType == subscribedToType || subscribedToType == typeof(IDomainEvent))
7776
{
7877
subscriber.HandleEvent(domainEvent);
7978
}
8079
}
8180
}
8281
finally
8382
{
84-
this.Publishing = false;
83+
this.publishing = false;
8584
}
8685
}
8786
}
8887

89-
public void PublishAll(ICollection<DomainEvent> domainEvents)
88+
public void PublishAll(ICollection<IDomainEvent> domainEvents)
9089
{
91-
foreach (DomainEvent domainEvent in domainEvents)
90+
foreach (var domainEvent in domainEvents)
9291
{
9392
this.Publish(domainEvent);
9493
}
9594
}
9695

9796
public void Reset()
9897
{
99-
if (!this.Publishing)
98+
if (!this.publishing)
10099
{
101100
this.Subscribers = null;
102101
}
103102
}
104103

105-
public void Subscribe(DomainEventSubscriber<DomainEvent> subscriber)
104+
public void Subscribe(IDomainEventSubscriber<IDomainEvent> subscriber)
106105
{
107-
if (!this.Publishing)
106+
if (!this.publishing)
108107
{
109108
this.Subscribers.Add(subscriber);
110109
}
111110
}
112111

113-
private bool HasSubscribers()
112+
bool HasSubscribers()
114113
{
115114
return this._subscribers != null && this.Subscribers.Count != 0;
116115
}

‎iddd_common/SaaSOvation.Common.Domain.Model/DomainEvent.cs ‎iddd_common/SaaSOvation.Common.Domain.Model/IDomainEvent.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ namespace SaaSOvation.Common.Domain.Model
1616
{
1717
using System;
1818

19-
public interface DomainEvent
19+
public interface IDomainEvent
2020
{
2121
int EventVersion { get; set; }
22-
2322
DateTime OccurredOn { get; set; }
2423
}
2524
}

‎iddd_common/SaaSOvation.Common.Domain.Model/DomainEventSubscriber.cs ‎iddd_common/SaaSOvation.Common.Domain.Model/IDomainEventSubscriber.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ namespace SaaSOvation.Common.Domain.Model
1616
{
1717
using System;
1818

19-
public interface DomainEventSubscriber<T> where T : DomainEvent
19+
public interface IDomainEventSubscriber<T> where T : IDomainEvent
2020
{
2121
void HandleEvent(T domainEvent);
22-
2322
Type SubscribedToEventType();
2423
}
2524
}

‎iddd_common/SaaSOvation.Common.Domain.Model/Identity.cs

+10-15
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace SaaSOvation.Common.Domain.Model
1616
{
1717
using System;
1818

19-
public abstract class Identity
19+
public abstract class Identity : IEquatable<Identity>
2020
{
2121
public Identity()
2222
{
@@ -30,26 +30,21 @@ public Identity(string id)
3030

3131
public string Id { get; private set; }
3232

33-
public override bool Equals(object anotherObject)
33+
public bool Equals(Identity id)
3434
{
35-
bool equalObjects = false;
36-
37-
if (anotherObject != null && this.GetType() == anotherObject.GetType())
38-
{
39-
Identity typedObject = (Identity)anotherObject;
40-
equalObjects = this.Id.Equals(typedObject.Id);
41-
}
35+
if (object.ReferenceEquals(this, id)) return true;
36+
if (object.ReferenceEquals(null, id)) return false;
37+
return this.Id.Equals(id.Id);
38+
}
4239

43-
return equalObjects;
40+
public override bool Equals(object anotherObject)
41+
{
42+
return Equals(anotherObject as Identity);
4443
}
4544

4645
public override int GetHashCode()
4746
{
48-
int hashCodeValue =
49-
+ (this.GetType().GetHashCode() * 907)
50-
+ this.Id.GetHashCode();
51-
52-
return hashCodeValue;
47+
return (this.GetType().GetHashCode() * 907) + this.Id.GetHashCode();
5348
}
5449

5550
public override string ToString()

‎iddd_common/SaaSOvation.Common.Domain.Model/LongRunningProcess/ProcessTimedOut.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace SaaSOvation.Common.Domain.Model.LongRunningProcess
1616
{
1717
using System;
1818

19-
public class ProcessTimedOut : DomainEvent
19+
public class ProcessTimedOut : IDomainEvent
2020
{
2121
public ProcessTimedOut(
2222
string tenantId,

‎iddd_common/iddd_common.csproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<ProjectGuid>{23B36FF3-B4FE-4765-815E-4943A737BC6D}</ProjectGuid>
99
<OutputType>Library</OutputType>
1010
<AppDesignerFolder>Properties</AppDesignerFolder>
11-
<RootNamespace>iddd_common</RootNamespace>
11+
<RootNamespace>SaaSOvation.Common</RootNamespace>
1212
<AssemblyName>iddd_common</AssemblyName>
1313
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
1414
<FileAlignment>512</FileAlignment>
@@ -42,9 +42,9 @@
4242
<ItemGroup>
4343
<Compile Include="SaaSOvation.Common.Domain.Model\AssertionConcern.cs" />
4444
<Compile Include="SaaSOvation.Common.Domain.Model\Entity.cs" />
45-
<Compile Include="SaaSOvation.Common.Domain.Model\DomainEvent.cs" />
45+
<Compile Include="SaaSOvation.Common.Domain.Model\IDomainEvent.cs" />
4646
<Compile Include="SaaSOvation.Common.Domain.Model\DomainEventPublisher.cs" />
47-
<Compile Include="SaaSOvation.Common.Domain.Model\DomainEventSubscriber.cs" />
47+
<Compile Include="SaaSOvation.Common.Domain.Model\IDomainEventSubscriber.cs" />
4848
<Compile Include="SaaSOvation.Common.Domain.Model\Identity.cs" />
4949
<Compile Include="SaaSOvation.Common.Domain.Model\LongRunningProcess\Process.cs" />
5050
<Compile Include="SaaSOvation.Common.Domain.Model\LongRunningProcess\ProcessId.cs" />
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,63 @@
1-
// Copyright 2012,2013 Vaughn Vernon
2-
//
3-
// Licensed under the Apache License, Version 2.0 (the "License");
4-
// you may not use this file except in compliance with the License.
5-
// You may obtain a copy of the License at
6-
//
7-
// http://www.apache.org/licenses/LICENSE-2.0
8-
//
9-
// Unless required by applicable law or agreed to in writing, software
10-
// distributed under the License is distributed on an "AS IS" BASIS,
11-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12-
// See the License for the specific language governing permissions and
13-
// limitations under the License.
14-
15-
namespace SaaSOvation.IdentityAccess.Domain.Model.Access
16-
{
17-
using SaaSOvation.Common.Domain.Model;
18-
using SaaSOvation.IdentityAccess.Domain.Model.Identity;
19-
20-
public class AuthorizationService
21-
{
22-
public AuthorizationService(
23-
UserRepository userRepository,
24-
GroupRepository groupRepository,
25-
RoleRepository roleRepository)
26-
{
27-
this.groupRepository = groupRepository;
28-
this.roleRepository = roleRepository;
29-
this.userRepository = userRepository;
30-
}
31-
32-
readonly GroupRepository groupRepository;
33-
readonly RoleRepository roleRepository;
34-
readonly UserRepository userRepository;
35-
36-
public bool IsUserInRole(TenantId tenantId, string username, string roleName)
37-
{
38-
AssertionConcern.AssertArgumentNotNull(tenantId, "TenantId must not be null.");
39-
AssertionConcern.AssertArgumentNotEmpty(username, "Username must not be provided.");
40-
AssertionConcern.AssertArgumentNotEmpty(roleName, "Role name must not be null.");
41-
42-
var user = this.userRepository.UserWithUsername(tenantId, username);
43-
return user == null ? false : this.IsUserInRole(user, roleName);
44-
}
45-
46-
public bool IsUserInRole(User user, string roleName)
47-
{
48-
AssertionConcern.AssertArgumentNotNull(user, "User must not be null.");
49-
AssertionConcern.AssertArgumentNotEmpty(roleName, "Role name must not be null.");
50-
51-
var authorized = false;
52-
if (user.Enabled)
53-
{
54-
var role = this.roleRepository.RoleNamed(user.TenantId, roleName);
55-
if (role != null)
56-
{
57-
authorized = role.IsInRole(user, new GroupMemberService(this.userRepository, this.groupRepository));
58-
}
59-
}
60-
return authorized;
61-
}
62-
}
63-
}
1+
// Copyright 2012,2013 Vaughn Vernon
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace SaaSOvation.IdentityAccess.Domain.Model.Access
16+
{
17+
using SaaSOvation.Common.Domain.Model;
18+
using SaaSOvation.IdentityAccess.Domain.Model.Identity;
19+
20+
public class AuthorizationService
21+
{
22+
public AuthorizationService(
23+
IUserRepository userRepository,
24+
IGroupRepository groupRepository,
25+
IRoleRepository roleRepository)
26+
{
27+
this.groupRepository = groupRepository;
28+
this.roleRepository = roleRepository;
29+
this.userRepository = userRepository;
30+
}
31+
32+
readonly IGroupRepository groupRepository;
33+
readonly IRoleRepository roleRepository;
34+
readonly IUserRepository userRepository;
35+
36+
public bool IsUserInRole(TenantId tenantId, string username, string roleName)
37+
{
38+
AssertionConcern.AssertArgumentNotNull(tenantId, "TenantId must not be null.");
39+
AssertionConcern.AssertArgumentNotEmpty(username, "Username must not be provided.");
40+
AssertionConcern.AssertArgumentNotEmpty(roleName, "Role name must not be null.");
41+
42+
var user = this.userRepository.UserWithUsername(tenantId, username);
43+
return user == null ? false : this.IsUserInRole(user, roleName);
44+
}
45+
46+
public bool IsUserInRole(User user, string roleName)
47+
{
48+
AssertionConcern.AssertArgumentNotNull(user, "User must not be null.");
49+
AssertionConcern.AssertArgumentNotEmpty(roleName, "Role name must not be null.");
50+
51+
var authorized = false;
52+
if (user.Enabled)
53+
{
54+
var role = this.roleRepository.RoleNamed(user.TenantId, roleName);
55+
if (role != null)
56+
{
57+
authorized = role.IsInRole(user, new GroupMemberService(this.userRepository, this.groupRepository));
58+
}
59+
}
60+
return authorized;
61+
}
62+
}
63+
}

‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Access/RoleRepository.cs ‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Access/IRoleRepository.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@ namespace SaaSOvation.IdentityAccess.Domain.Model.Access
1818
using SaaSOvation.Common.Domain.Model;
1919
using SaaSOvation.IdentityAccess.Domain.Model.Identity;
2020

21-
public interface RoleRepository
21+
public interface IRoleRepository
2222
{
2323
void Add(Role role);
24-
2524
Role RoleNamed(TenantId identity, string roleName);
2625
}
2726
}
Original file line numberDiff line numberDiff line change
@@ -1,152 +1,146 @@
1-
// Copyright 2012,2013 Vaughn Vernon
2-
//
3-
// Licensed under the Apache License, Version 2.0 (the "License");
4-
// you may not use this file except in compliance with the License.
5-
// You may obtain a copy of the License at
6-
//
7-
// http://www.apache.org/licenses/LICENSE-2.0
8-
//
9-
// Unless required by applicable law or agreed to in writing, software
10-
// distributed under the License is distributed on an "AS IS" BASIS,
11-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12-
// See the License for the specific language governing permissions and
13-
// limitations under the License.
14-
15-
namespace SaaSOvation.IdentityAccess.Domain.Model.Access
16-
{
17-
using System;
18-
using SaaSOvation.Common.Domain.Model;
19-
using SaaSOvation.IdentityAccess.Domain.Model.Identity;
20-
21-
public class Role
22-
{
23-
public Role(TenantId tenantId, string name, string description, bool supportsNesting)
24-
{
25-
this.Description = description;
26-
this.Name = name;
27-
this.SupportsNesting = supportsNesting;
28-
this.TenantId = tenantId;
29-
this.group = CreateInternalGroup();
30-
}
31-
32-
readonly Group group;
33-
34-
Group CreateInternalGroup()
35-
{
36-
var groupName = Group.ROLE_GROUP_PREFIX + Guid.NewGuid().ToString();
37-
return new Group(this.TenantId, groupName, "Role backing group for: " + this.Name);
38-
}
39-
40-
public string Description { get; private set; }
41-
42-
public string Name { get; private set; }
43-
44-
public bool SupportsNesting { get; private set; }
45-
46-
public TenantId TenantId { get; private set; }
47-
48-
49-
public void AssignGroup(Group group, GroupMemberService groupMemberService)
50-
{
51-
AssertionConcern.AssertStateTrue(this.SupportsNesting, "This role does not support group nesting.");
52-
AssertionConcern.AssertArgumentNotNull(group, "Group must not be null.");
53-
AssertionConcern.AssertArgumentEquals(this.TenantId, group.TenantId, "Wrong tenant for this group.");
54-
55-
this.group.AddGroup(group, groupMemberService);
56-
57-
DomainEventPublisher
58-
.Instance
59-
.Publish(new GroupAssignedToRole(
60-
this.TenantId,
61-
this.Name,
62-
group.Name));
63-
}
64-
65-
public void AssignUser(User user)
66-
{
67-
AssertionConcern.AssertArgumentNotNull(user, "User must not be null.");
68-
AssertionConcern.AssertArgumentEquals(this.TenantId, user.TenantId, "Wrong tenant for this user.");
69-
70-
this.group.AddUser(user);
71-
72-
DomainEventPublisher
73-
.Instance
74-
.Publish(new UserAssignedToRole(
75-
this.TenantId,
76-
this.Name,
77-
user.Username,
78-
user.Person.Name.FirstName,
79-
user.Person.Name.LastName,
80-
user.Person.EmailAddress.Address));
81-
}
82-
83-
public bool IsInRole(User user, GroupMemberService groupMemberService)
84-
{
85-
return this.group.IsMember(user, groupMemberService);
86-
}
87-
88-
public void UnassignGroup(Group group)
89-
{
90-
AssertionConcern.AssertStateTrue(this.SupportsNesting, "This role does not support group nesting.");
91-
AssertionConcern.AssertArgumentNotNull(group, "Group must not be null.");
92-
AssertionConcern.AssertArgumentEquals(this.TenantId, group.TenantId, "Wrong tenant for this group.");
93-
94-
this.group.RemoveGroup(group);
95-
96-
DomainEventPublisher
97-
.Instance
98-
.Publish(new GroupUnassignedFromRole(
99-
this.TenantId,
100-
this.Name,
101-
group.Name));
102-
}
103-
104-
public void UnassignUser(User user)
105-
{
106-
AssertionConcern.AssertArgumentNotNull(user, "User must not be null.");
107-
AssertionConcern.AssertArgumentEquals(this.TenantId, user.TenantId, "Wrong tenant for this user.");
108-
109-
this.group.RemoveUser(user);
110-
111-
DomainEventPublisher
112-
.Instance
113-
.Publish(new UserUnassignedFromRole(
114-
this.TenantId,
115-
this.Name,
116-
user.Username));
117-
}
118-
119-
public override bool Equals(Object anotherObject)
120-
{
121-
var equalObjects = false;
122-
123-
if (anotherObject != null && this.GetType() == anotherObject.GetType())
124-
{
125-
var typedObject = (Role)anotherObject;
126-
equalObjects =
127-
this.TenantId.Equals(typedObject.TenantId) &&
128-
this.Name.Equals(typedObject.Name);
129-
}
130-
131-
return equalObjects;
132-
}
133-
134-
public override int GetHashCode()
135-
{
136-
int hashCodeValue =
137-
+ (18723 * 233)
138-
+ this.TenantId.GetHashCode()
139-
+ this.Name.GetHashCode();
140-
141-
return hashCodeValue;
142-
}
143-
144-
public override string ToString()
145-
{
146-
return "Role [tenantId=" + TenantId + ", name=" + Name
147-
+ ", description=" + Description
148-
+ ", supportsNesting=" + SupportsNesting
149-
+ ", group=" + group + "]";
150-
}
151-
}
152-
}
1+
// Copyright 2012,2013 Vaughn Vernon
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace SaaSOvation.IdentityAccess.Domain.Model.Access
16+
{
17+
using System;
18+
using SaaSOvation.Common.Domain.Model;
19+
using SaaSOvation.IdentityAccess.Domain.Model.Identity;
20+
21+
public class Role : IEquatable<Role>
22+
{
23+
public Role(TenantId tenantId, string name, string description, bool supportsNesting)
24+
{
25+
this.Description = description;
26+
this.Name = name;
27+
this.SupportsNesting = supportsNesting;
28+
this.TenantId = tenantId;
29+
this.group = CreateInternalGroup();
30+
}
31+
32+
readonly Group group;
33+
34+
Group CreateInternalGroup()
35+
{
36+
var groupName = Group.ROLE_GROUP_PREFIX + Guid.NewGuid().ToString();
37+
return new Group(this.TenantId, groupName, "Role backing group for: " + this.Name);
38+
}
39+
40+
public string Description { get; private set; }
41+
42+
public string Name { get; private set; }
43+
44+
public bool SupportsNesting { get; private set; }
45+
46+
public TenantId TenantId { get; private set; }
47+
48+
public void AssignGroup(Group group, GroupMemberService groupMemberService)
49+
{
50+
AssertionConcern.AssertStateTrue(this.SupportsNesting, "This role does not support group nesting.");
51+
AssertionConcern.AssertArgumentNotNull(group, "Group must not be null.");
52+
AssertionConcern.AssertArgumentEquals(this.TenantId, group.TenantId, "Wrong tenant for this group.");
53+
54+
this.group.AddGroup(group, groupMemberService);
55+
56+
DomainEventPublisher
57+
.Instance
58+
.Publish(new GroupAssignedToRole(
59+
this.TenantId,
60+
this.Name,
61+
group.Name));
62+
}
63+
64+
public void AssignUser(User user)
65+
{
66+
AssertionConcern.AssertArgumentNotNull(user, "User must not be null.");
67+
AssertionConcern.AssertArgumentEquals(this.TenantId, user.TenantId, "Wrong tenant for this user.");
68+
69+
this.group.AddUser(user);
70+
71+
DomainEventPublisher
72+
.Instance
73+
.Publish(new UserAssignedToRole(
74+
this.TenantId,
75+
this.Name,
76+
user.Username,
77+
user.Person.Name.FirstName,
78+
user.Person.Name.LastName,
79+
user.Person.EmailAddress.Address));
80+
}
81+
82+
public bool IsInRole(User user, GroupMemberService groupMemberService)
83+
{
84+
return this.group.IsMember(user, groupMemberService);
85+
}
86+
87+
public void UnassignGroup(Group group)
88+
{
89+
AssertionConcern.AssertStateTrue(this.SupportsNesting, "This role does not support group nesting.");
90+
AssertionConcern.AssertArgumentNotNull(group, "Group must not be null.");
91+
AssertionConcern.AssertArgumentEquals(this.TenantId, group.TenantId, "Wrong tenant for this group.");
92+
93+
this.group.RemoveGroup(group);
94+
95+
DomainEventPublisher
96+
.Instance
97+
.Publish(new GroupUnassignedFromRole(
98+
this.TenantId,
99+
this.Name,
100+
group.Name));
101+
}
102+
103+
public void UnassignUser(User user)
104+
{
105+
AssertionConcern.AssertArgumentNotNull(user, "User must not be null.");
106+
AssertionConcern.AssertArgumentEquals(this.TenantId, user.TenantId, "Wrong tenant for this user.");
107+
108+
this.group.RemoveUser(user);
109+
110+
DomainEventPublisher
111+
.Instance
112+
.Publish(new UserUnassignedFromRole(
113+
this.TenantId,
114+
this.Name,
115+
user.Username));
116+
}
117+
118+
public bool Equals(Role role)
119+
{
120+
if (object.ReferenceEquals(this, role)) return true;
121+
if (object.ReferenceEquals(null, role)) return false;
122+
return this.TenantId.Equals(role.TenantId) && this.Name.Equals(role.Name);
123+
}
124+
125+
public override bool Equals(object anotherObject)
126+
{
127+
return Equals(anotherObject as Role);
128+
}
129+
130+
public override int GetHashCode()
131+
{
132+
return
133+
+ (18723 * 233)
134+
+ this.TenantId.GetHashCode()
135+
+ this.Name.GetHashCode();
136+
}
137+
138+
public override string ToString()
139+
{
140+
return "Role [tenantId=" + TenantId + ", name=" + Name
141+
+ ", description=" + Description
142+
+ ", supportsNesting=" + SupportsNesting
143+
+ ", group=" + group + "]";
144+
}
145+
}
146+
}

‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Access/RoleEvents.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace SaaSOvation.IdentityAccess.Domain.Model.Access
1818
using SaaSOvation.Common.Domain.Model;
1919
using SaaSOvation.IdentityAccess.Domain.Model.Identity;
2020

21-
public class GroupAssignedToRole : DomainEvent
21+
public class GroupAssignedToRole : IDomainEvent
2222
{
2323
public GroupAssignedToRole(TenantId tenantId, string roleName, string groupName)
2424
{
@@ -40,7 +40,7 @@ public GroupAssignedToRole(TenantId tenantId, string roleName, string groupName)
4040
public TenantId TenantId;
4141
}
4242

43-
public class GroupUnassignedFromRole : DomainEvent
43+
public class GroupUnassignedFromRole : IDomainEvent
4444
{
4545
public GroupUnassignedFromRole(TenantId tenantId, string roleName, string groupName)
4646
{
@@ -62,7 +62,7 @@ public GroupUnassignedFromRole(TenantId tenantId, string roleName, string groupN
6262
public TenantId TenantId;
6363
}
6464

65-
public class RoleProvisioned : DomainEvent
65+
public class RoleProvisioned : IDomainEvent
6666
{
6767
public RoleProvisioned(TenantId tenantId, string name)
6868
{
@@ -81,7 +81,7 @@ public RoleProvisioned(TenantId tenantId, string name)
8181
public string TenantId { get; private set; }
8282
}
8383

84-
public class UserAssignedToRole : DomainEvent
84+
public class UserAssignedToRole : IDomainEvent
8585
{
8686
public UserAssignedToRole(
8787
TenantId tenantId,
@@ -118,7 +118,7 @@ public UserAssignedToRole(
118118
public string Username { get; private set; }
119119
}
120120

121-
public class UserUnassignedFromRole : DomainEvent
121+
public class UserUnassignedFromRole : IDomainEvent
122122
{
123123
public UserUnassignedFromRole(TenantId tenantId, string roleName, string username)
124124
{
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,59 @@
1-
// Copyright 2012,2013 Vaughn Vernon
2-
//
3-
// Licensed under the Apache License, Version 2.0 (the "License");
4-
// you may not use this file except in compliance with the License.
5-
// You may obtain a copy of the License at
6-
//
7-
// http://www.apache.org/licenses/LICENSE-2.0
8-
//
9-
// Unless required by applicable law or agreed to in writing, software
10-
// distributed under the License is distributed on an "AS IS" BASIS,
11-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12-
// See the License for the specific language governing permissions and
13-
// limitations under the License.
14-
15-
namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
16-
{
17-
using System;
18-
using SaaSOvation.Common.Domain.Model;
19-
20-
public class AuthenticationService
21-
{
22-
public AuthenticationService(
23-
TenantRepository tenantRepository,
24-
UserRepository userRepository,
25-
EncryptionService encryptionService)
26-
{
27-
this.encryptionService = encryptionService;
28-
this.tenantRepository = tenantRepository;
29-
this.userRepository = userRepository;
30-
}
31-
32-
EncryptionService encryptionService;
33-
TenantRepository tenantRepository;
34-
UserRepository userRepository;
35-
36-
public UserDescriptor Authenticate(TenantId tenantId, string username, string password)
37-
{
38-
AssertionConcern.AssertArgumentNotNull(tenantId, "TenantId must not be null.");
39-
AssertionConcern.AssertArgumentNotEmpty(username, "Username must be provided.");
40-
AssertionConcern.AssertArgumentNotEmpty(password, "Password must be provided.");
41-
42-
var userDescriptor = UserDescriptor.NullDescriptorInstance();
43-
44-
var tenant = this.tenantRepository.TenantOfId(tenantId);
45-
46-
if (tenant != null && tenant.Active)
47-
{
48-
var encryptedPassword = this.encryptionService.EncryptedValue(password);
49-
var user = this.userRepository.UserFromAuthenticCredentials(tenantId, username, encryptedPassword);
50-
if (user != null && user.Enabled)
51-
{
52-
userDescriptor = user.UserDescriptor;
53-
}
54-
}
55-
56-
return userDescriptor;
57-
}
58-
}
59-
}
1+
// Copyright 2012,2013 Vaughn Vernon
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
16+
{
17+
using System;
18+
using SaaSOvation.Common.Domain.Model;
19+
20+
public class AuthenticationService
21+
{
22+
public AuthenticationService(
23+
ITenantRepository tenantRepository,
24+
IUserRepository userRepository,
25+
IEncryptionService encryptionService)
26+
{
27+
this.encryptionService = encryptionService;
28+
this.tenantRepository = tenantRepository;
29+
this.userRepository = userRepository;
30+
}
31+
32+
readonly IEncryptionService encryptionService;
33+
readonly ITenantRepository tenantRepository;
34+
readonly IUserRepository userRepository;
35+
36+
public UserDescriptor Authenticate(TenantId tenantId, string username, string password)
37+
{
38+
AssertionConcern.AssertArgumentNotNull(tenantId, "TenantId must not be null.");
39+
AssertionConcern.AssertArgumentNotEmpty(username, "Username must be provided.");
40+
AssertionConcern.AssertArgumentNotEmpty(password, "Password must be provided.");
41+
42+
var userDescriptor = UserDescriptor.NullDescriptorInstance();
43+
44+
var tenant = this.tenantRepository.TenantOfId(tenantId);
45+
46+
if (tenant != null && tenant.Active)
47+
{
48+
var encryptedPassword = this.encryptionService.EncryptedValue(password);
49+
var user = this.userRepository.UserFromAuthenticCredentials(tenantId, username, encryptedPassword);
50+
if (user != null && user.Enabled)
51+
{
52+
userDescriptor = user.UserDescriptor;
53+
}
54+
}
55+
56+
return userDescriptor;
57+
}
58+
}
59+
}

‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/ContactInformation.cs

+3-4
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,12 @@ public override bool Equals(Object anotherObject)
106106

107107
public override int GetHashCode()
108108
{
109-
int hashCodeValue =
109+
return
110110
+ (73213 * 173)
111111
+ this.EmailAddress.GetHashCode()
112112
+ this.PostalAddress.GetHashCode()
113113
+ this.PrimaryTelephone.GetHashCode()
114114
+ (this.SecondaryTelephone == null ? 0:this.SecondaryTelephone.GetHashCode());
115-
116-
return hashCodeValue;
117115
}
118116

119117
public override string ToString()
@@ -141,7 +139,8 @@ internal EmailAddress()
141139
{
142140
}
143141

144-
private string _address;
142+
string _address;
143+
145144
public string Address
146145
{
147146
get

‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/GroupEvents.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
1717
using System;
1818
using SaaSOvation.Common.Domain.Model;
1919

20-
public class GroupGroupAdded : DomainEvent
20+
public class GroupGroupAdded : IDomainEvent
2121
{
2222
public GroupGroupAdded(TenantId tenantId, string groupName, string nestedGroupName)
2323
{
@@ -39,7 +39,7 @@ public GroupGroupAdded(TenantId tenantId, string groupName, string nestedGroupNa
3939
public string TenantId { get; private set; }
4040
}
4141

42-
public class GroupGroupRemoved : DomainEvent
42+
public class GroupGroupRemoved : IDomainEvent
4343
{
4444
public GroupGroupRemoved(TenantId tenantId, string groupName, string nestedGroupName)
4545
{
@@ -61,7 +61,7 @@ public GroupGroupRemoved(TenantId tenantId, string groupName, string nestedGroup
6161
public string TenantId { get; private set; }
6262
}
6363

64-
public class GroupUserAdded : DomainEvent
64+
public class GroupUserAdded : IDomainEvent
6565
{
6666
public GroupUserAdded(TenantId tenantId, string groupName, string username)
6767
{
@@ -83,7 +83,7 @@ public GroupUserAdded(TenantId tenantId, string groupName, string username)
8383
public string Username { get; private set; }
8484
}
8585

86-
public class GroupUserRemoved : DomainEvent
86+
public class GroupUserRemoved : IDomainEvent
8787
{
8888
public GroupUserRemoved(TenantId tenantId, string groupName, string username)
8989
{
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,81 @@
1-
// Copyright 2012,2013 Vaughn Vernon
2-
//
3-
// Licensed under the Apache License, Version 2.0 (the "License");
4-
// you may not use this file except in compliance with the License.
5-
// You may obtain a copy of the License at
6-
//
7-
// http://www.apache.org/licenses/LICENSE-2.0
8-
//
9-
// Unless required by applicable law or agreed to in writing, software
10-
// distributed under the License is distributed on an "AS IS" BASIS,
11-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12-
// See the License for the specific language governing permissions and
13-
// limitations under the License.
14-
15-
namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
16-
{
17-
using System;
18-
using System.Linq;
19-
20-
public class GroupMemberService
21-
{
22-
public GroupMemberService(UserRepository userRepository, GroupRepository groupRepository)
23-
{
24-
this.groupRepository = groupRepository;
25-
this.userRepository = userRepository;
26-
}
27-
28-
readonly GroupRepository groupRepository;
29-
readonly UserRepository userRepository;
30-
31-
public bool ConfirmUser(Group group, User user)
32-
{
33-
var confirmedUser = this.userRepository.UserWithUsername(group.TenantId, user.Username);
34-
var userConfirmed = confirmedUser == null || !confirmedUser.Enabled;
35-
return userConfirmed;
36-
}
37-
38-
public bool IsMemberGroup(Group group, GroupMember memberGroup)
39-
{
40-
var isMember = false;
41-
42-
foreach (var member in group.GroupMembers.Where(x => x.IsGroup()))
43-
{
44-
if (memberGroup.Equals(member))
45-
{
46-
isMember = true;
47-
}
48-
else
49-
{
50-
var nestedGroup = this.groupRepository.GroupNamed(member.TenantId, member.Name);
51-
if (nestedGroup != null)
52-
{
53-
isMember = IsMemberGroup(nestedGroup, memberGroup);
54-
}
55-
}
56-
57-
if (isMember)
58-
{
59-
break;
60-
}
61-
}
62-
63-
return isMember;
64-
}
65-
66-
public bool IsUserInNestedGroup(Group group, User user)
67-
{
68-
foreach (var member in group.GroupMembers.Where(x => x.IsGroup()))
69-
{
70-
var nestedGroup = this.groupRepository.GroupNamed(member.TenantId, member.Name);
71-
if (nestedGroup != null)
72-
{
73-
var isInNestedGroup = nestedGroup.IsMember(user, this);
74-
if (isInNestedGroup)
75-
return true;
76-
}
77-
}
78-
return false;
79-
}
80-
}
81-
}
1+
// Copyright 2012,2013 Vaughn Vernon
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
16+
{
17+
using System;
18+
using System.Linq;
19+
20+
public class GroupMemberService
21+
{
22+
public GroupMemberService(IUserRepository userRepository, IGroupRepository groupRepository)
23+
{
24+
this.groupRepository = groupRepository;
25+
this.userRepository = userRepository;
26+
}
27+
28+
readonly IGroupRepository groupRepository;
29+
readonly IUserRepository userRepository;
30+
31+
public bool ConfirmUser(Group group, User user)
32+
{
33+
var confirmedUser = this.userRepository.UserWithUsername(group.TenantId, user.Username);
34+
var userConfirmed = confirmedUser == null || !confirmedUser.Enabled;
35+
return userConfirmed;
36+
}
37+
38+
public bool IsMemberGroup(Group group, GroupMember memberGroup)
39+
{
40+
var isMember = false;
41+
42+
foreach (var member in group.GroupMembers.Where(x => x.IsGroup()))
43+
{
44+
if (memberGroup.Equals(member))
45+
{
46+
isMember = true;
47+
}
48+
else
49+
{
50+
var nestedGroup = this.groupRepository.GroupNamed(member.TenantId, member.Name);
51+
if (nestedGroup != null)
52+
{
53+
isMember = IsMemberGroup(nestedGroup, memberGroup);
54+
}
55+
}
56+
57+
if (isMember)
58+
{
59+
break;
60+
}
61+
}
62+
63+
return isMember;
64+
}
65+
66+
public bool IsUserInNestedGroup(Group group, User user)
67+
{
68+
foreach (var member in group.GroupMembers.Where(x => x.IsGroup()))
69+
{
70+
var nestedGroup = this.groupRepository.GroupNamed(member.TenantId, member.Name);
71+
if (nestedGroup != null)
72+
{
73+
var isInNestedGroup = nestedGroup.IsMember(user, this);
74+
if (isInNestedGroup)
75+
return true;
76+
}
77+
}
78+
return false;
79+
}
80+
}
81+
}

‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/EncryptionService.cs ‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/IEncryptionService.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
1616
{
1717
using System;
1818

19-
public interface EncryptionService
19+
public interface IEncryptionService
2020
{
2121
string EncryptedValue(string plainTextValue);
2222
}

‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/GroupRepository.cs ‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/IGroupRepository.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
1717
using System;
1818
using SaaSOvation.Common.Domain.Model;
1919

20-
public interface GroupRepository
20+
public interface IGroupRepository
2121
{
2222
Group GroupNamed(TenantId identity, string p);
2323
}

‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/TenantRepository.cs ‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/ITenantRepository.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,9 @@ namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
1717
using System;
1818
using SaaSOvation.Common.Domain.Model;
1919

20-
public interface TenantRepository
20+
public interface ITenantRepository
2121
{
2222
void Add(Tenant tenant);
23-
2423
Tenant TenantOfId(TenantId tenantId);
2524
}
2625
}

‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/UserRepository.cs ‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/IUserRepository.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
1717
using System;
1818
using SaaSOvation.Common.Domain.Model;
1919

20-
public interface UserRepository
20+
public interface IUserRepository
2121
{
2222
void Add(User user);
2323

‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/PasswordService.cs

+16-16
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,17 @@ public string GenerateStrongPassword()
3333
{
3434
String generatedPassword = null;
3535

36-
string password = "";
36+
var password = "";
3737

38-
Random random = new Random();
38+
var random = new Random();
3939

40-
bool isStrong = false;
40+
var isStrong = false;
4141

42-
int index = 0;
42+
var index = 0;
4343

4444
while (!isStrong)
4545
{
46-
int opt = random.Next(4);
46+
var opt = random.Next(4);
4747

4848
switch (opt)
4949
{
@@ -91,7 +91,7 @@ public bool IsWeak(string plainTextPassword)
9191
return this.CalculatePasswordStrength(plainTextPassword) < STRONG_THRESHOLD;
9292
}
9393

94-
private int CalculatePasswordStrength(String plainTextPassword)
94+
int CalculatePasswordStrength(String plainTextPassword)
9595
{
9696
AssertionConcern.AssertArgumentNotNull(plainTextPassword, "Password strength cannot be tested on null.");
9797

@@ -106,21 +106,21 @@ private int CalculatePasswordStrength(String plainTextPassword)
106106
strength += (length - 7);
107107
}
108108

109-
int digitCount = 0;
110-
int letterCount = 0;
111-
int lowerCount = 0;
112-
int upperCount = 0;
113-
int symbolCount = 0;
109+
var digitCount = 0;
110+
var letterCount = 0;
111+
var lowerCount = 0;
112+
var upperCount = 0;
113+
var symbolCount = 0;
114114

115-
for (int idx = 0; idx < length; ++idx)
115+
for (var idx = 0; idx < length; ++idx)
116116
{
117-
char ch = plainTextPassword[idx];
117+
var ch = plainTextPassword[idx];
118118

119-
if (Char.IsLetter(ch))
119+
if (char.IsLetter(ch))
120120
{
121121
++letterCount;
122122

123-
if (Char.IsUpper(ch))
123+
if (char.IsUpper(ch))
124124
{
125125
++upperCount;
126126
}
@@ -129,7 +129,7 @@ private int CalculatePasswordStrength(String plainTextPassword)
129129
++lowerCount;
130130
}
131131
}
132-
else if (Char.IsDigit(ch))
132+
else if (char.IsDigit(ch))
133133
{
134134
++digitCount;
135135
}
Original file line numberDiff line numberDiff line change
@@ -1,197 +1,199 @@
1-
// Copyright 2012,2013 Vaughn Vernon
2-
//
3-
// Licensed under the Apache License, Version 2.0 (the "License");
4-
// you may not use this file except in compliance with the License.
5-
// You may obtain a copy of the License at
6-
//
7-
// http://www.apache.org/licenses/LICENSE-2.0
8-
//
9-
// Unless required by applicable law or agreed to in writing, software
10-
// distributed under the License is distributed on an "AS IS" BASIS,
11-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12-
// See the License for the specific language governing permissions and
13-
// limitations under the License.
14-
15-
namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
16-
{
17-
using System;
18-
using System.Collections.Generic;
19-
using System.Linq;
20-
using SaaSOvation.Common.Domain.Model;
21-
using SaaSOvation.IdentityAccess.Domain.Model.Access;
22-
23-
public class Tenant
24-
{
25-
public Tenant(string name, string description, bool active)
26-
{
27-
this.Active = active;
28-
this.Description = description;
29-
this.Name = name;
30-
this.registrationInvitations = new HashSet<RegistrationInvitation>();
31-
this.TenantId = new TenantId();
32-
}
33-
34-
public bool Active { get; private set; }
35-
36-
public string Description { get; private set; }
37-
38-
public string Name { get; private set; }
39-
40-
public TenantId TenantId { get; private set; }
41-
42-
ISet<RegistrationInvitation> registrationInvitations;
43-
44-
public void Activate()
45-
{
46-
if (!this.Active)
47-
{
48-
this.Active = true;
49-
DomainEventPublisher.Instance.Publish(new TenantActivated(this.TenantId));
50-
}
51-
}
52-
53-
public ICollection<InvitationDescriptor> AllAvailableRegistrationInvitations()
54-
{
55-
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
56-
return AllRegistrationInvitationsFor(true);
57-
}
58-
59-
public ICollection<InvitationDescriptor> AllUnavailableRegistrationInvitations()
60-
{
61-
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
62-
return AllRegistrationInvitationsFor(false);
63-
}
64-
65-
public void Deactivate()
66-
{
67-
if (this.Active)
68-
{
69-
this.Active = false;
70-
DomainEventPublisher.Instance.Publish(new TenantDeactivated(this.TenantId));
71-
}
72-
}
73-
74-
public bool IsRegistrationAvailableThrough(string invitationIdentifier)
75-
{
76-
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
77-
var invitation = InvitationOf(invitationIdentifier);
78-
return invitation == null ? false : invitation.IsAvailable();
79-
}
80-
81-
public RegistrationInvitation OfferRegistrationInvitation(string description)
82-
{
83-
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
84-
AssertionConcern.AssertArgumentTrue(this.IsRegistrationAvailableThrough(description), "Invitation already exists.");
85-
86-
var invitation = new RegistrationInvitation(this.TenantId, new Guid().ToString(), description);
87-
88-
AssertionConcern.AssertStateTrue(this.registrationInvitations.Add(invitation), "The invitation should have been added.");
89-
90-
return invitation;
91-
}
92-
93-
public Group ProvisionGroup(string name, string description)
94-
{
95-
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
96-
97-
var group = new Group(this.TenantId, name, description);
98-
99-
DomainEventPublisher.Instance.Publish(new GroupProvisioned(this.TenantId, name));
100-
101-
return group;
102-
}
103-
104-
public Role ProvisionRole(string name, string description)
105-
{
106-
return ProvisionRole(name, description, false);
107-
}
108-
109-
Role ProvisionRole(string name, string description, bool supportsNesting)
110-
{
111-
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
112-
113-
var role = new Role(this.TenantId, name, description, supportsNesting);
114-
115-
DomainEventPublisher.Instance.Publish(new RoleProvisioned(this.TenantId, name));
116-
117-
return role;
118-
}
119-
120-
public RegistrationInvitation RedefineRegistrationInvitationAs(string invitationIdentifier)
121-
{
122-
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
123-
var invitation = InvitationOf(invitationIdentifier);
124-
if (invitation != null)
125-
{
126-
invitation.RedefineAs().OpenEnded();
127-
}
128-
return invitation;
129-
}
130-
131-
public User RegisterUser(string invitationIdentifier, string username, string password, Enablement enablement, Person person)
132-
{
133-
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
134-
User user = null;
135-
if (IsRegistrationAvailableThrough(invitationIdentifier))
136-
{
137-
// ensure same tenant
138-
person.TenantId = this.TenantId;
139-
user = new User(this.TenantId, username, password, enablement, person);
140-
}
141-
return user;
142-
}
143-
144-
public void WithdrawInvitation(string invitationIdentifier)
145-
{
146-
var invitation = InvitationOf(invitationIdentifier);
147-
if (invitation != null)
148-
{
149-
this.registrationInvitations.Remove(invitation);
150-
}
151-
}
152-
153-
List<InvitationDescriptor> AllRegistrationInvitationsFor(bool isAvailable)
154-
{
155-
return this.registrationInvitations
156-
.Where(x => x.IsAvailable() == isAvailable)
157-
.Select(x => x.ToDescriptor())
158-
.ToList();
159-
}
160-
161-
RegistrationInvitation InvitationOf(string invitationIdentifier)
162-
{
163-
return this.registrationInvitations.FirstOrDefault(x => x.IsIdentifiedBy(invitationIdentifier));
164-
}
165-
166-
public override bool Equals(object anotherObject)
167-
{
168-
var equalObjects = false;
169-
if (anotherObject != null && this.GetType() == anotherObject.GetType())
170-
{
171-
var typedObject = (Tenant)anotherObject;
172-
equalObjects =
173-
this.TenantId.Equals(typedObject.TenantId) &&
174-
this.Name.Equals(typedObject.Name);
175-
}
176-
return equalObjects;
177-
}
178-
179-
public override int GetHashCode()
180-
{
181-
return
182-
+(48123 * 257)
183-
+ this.TenantId.GetHashCode()
184-
+ this.Name.GetHashCode();
185-
}
186-
187-
public override string ToString()
188-
{
189-
return "Tenant ["
190-
+ ", tenantId=" + TenantId
191-
+ ", name=" + Name
192-
+ ", description=" + Description
193-
+ ", active=" + Active
194-
+ "]";
195-
}
196-
}
197-
}
1+
// Copyright 2012,2013 Vaughn Vernon
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
16+
{
17+
using System;
18+
using System.Collections.Generic;
19+
using System.Linq;
20+
using SaaSOvation.Common.Domain.Model;
21+
using SaaSOvation.IdentityAccess.Domain.Model.Access;
22+
23+
public class Tenant
24+
{
25+
public Tenant(string name, string description, bool active)
26+
{
27+
this.Active = active;
28+
this.Description = description;
29+
this.Name = name;
30+
this.registrationInvitations = new HashSet<RegistrationInvitation>();
31+
this.TenantId = new TenantId();
32+
}
33+
34+
public bool Active { get; private set; }
35+
36+
public string Description { get; private set; }
37+
38+
public string Name { get; private set; }
39+
40+
public TenantId TenantId { get; private set; }
41+
42+
ISet<RegistrationInvitation> registrationInvitations;
43+
44+
public void Activate()
45+
{
46+
if (!this.Active)
47+
{
48+
this.Active = true;
49+
DomainEventPublisher.Instance.Publish(new TenantActivated(this.TenantId));
50+
}
51+
}
52+
53+
public ICollection<InvitationDescriptor> AllAvailableRegistrationInvitations()
54+
{
55+
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
56+
return AllRegistrationInvitationsFor(true);
57+
}
58+
59+
public ICollection<InvitationDescriptor> AllUnavailableRegistrationInvitations()
60+
{
61+
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
62+
return AllRegistrationInvitationsFor(false);
63+
}
64+
65+
public void Deactivate()
66+
{
67+
if (this.Active)
68+
{
69+
this.Active = false;
70+
DomainEventPublisher.Instance.Publish(new TenantDeactivated(this.TenantId));
71+
}
72+
}
73+
74+
public bool IsRegistrationAvailableThrough(string invitationIdentifier)
75+
{
76+
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
77+
var invitation = InvitationOf(invitationIdentifier);
78+
return invitation == null ? false : invitation.IsAvailable();
79+
}
80+
81+
public RegistrationInvitation OfferRegistrationInvitation(string description)
82+
{
83+
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
84+
AssertionConcern.AssertArgumentTrue(IsRegistrationAvailableThrough(description), "Invitation already exists.");
85+
86+
var invitation = new RegistrationInvitation(this.TenantId, new Guid().ToString(), description);
87+
88+
AssertionConcern.AssertStateTrue(this.registrationInvitations.Add(invitation), "The invitation should have been added.");
89+
90+
return invitation;
91+
}
92+
93+
public Group ProvisionGroup(string name, string description)
94+
{
95+
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
96+
97+
var group = new Group(this.TenantId, name, description);
98+
99+
DomainEventPublisher.Instance.Publish(new GroupProvisioned(this.TenantId, name));
100+
101+
return group;
102+
}
103+
104+
public Role ProvisionRole(string name, string description)
105+
{
106+
return ProvisionRole(name, description, false);
107+
}
108+
109+
Role ProvisionRole(string name, string description, bool supportsNesting)
110+
{
111+
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
112+
113+
var role = new Role(this.TenantId, name, description, supportsNesting);
114+
115+
DomainEventPublisher.Instance.Publish(new RoleProvisioned(this.TenantId, name));
116+
117+
return role;
118+
}
119+
120+
public RegistrationInvitation RedefineRegistrationInvitationAs(string invitationIdentifier)
121+
{
122+
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
123+
var invitation = InvitationOf(invitationIdentifier);
124+
if (invitation != null)
125+
{
126+
invitation.RedefineAs().OpenEnded();
127+
}
128+
return invitation;
129+
}
130+
131+
public User RegisterUser(string invitationIdentifier, string username, string password, Enablement enablement, Person person)
132+
{
133+
AssertionConcern.AssertStateTrue(this.Active, "Tenant is not active.");
134+
User user = null;
135+
if (IsRegistrationAvailableThrough(invitationIdentifier))
136+
{
137+
// ensure same tenant
138+
person.TenantId = this.TenantId;
139+
user = new User(this.TenantId, username, password, enablement, person);
140+
}
141+
return user;
142+
}
143+
144+
public void WithdrawInvitation(string invitationIdentifier)
145+
{
146+
var invitation = InvitationOf(invitationIdentifier);
147+
if (invitation != null)
148+
{
149+
this.registrationInvitations.Remove(invitation);
150+
}
151+
}
152+
153+
List<InvitationDescriptor> AllRegistrationInvitationsFor(bool isAvailable)
154+
{
155+
return this.registrationInvitations
156+
.Where(x => x.IsAvailable() == isAvailable)
157+
.Select(x => x.ToDescriptor())
158+
.ToList();
159+
}
160+
161+
RegistrationInvitation InvitationOf(string invitationIdentifier)
162+
{
163+
return this.registrationInvitations.FirstOrDefault(x => x.IsIdentifiedBy(invitationIdentifier));
164+
}
165+
166+
167+
168+
public override bool Equals(object anotherObject)
169+
{
170+
var equalObjects = false;
171+
if (anotherObject != null && this.GetType() == anotherObject.GetType())
172+
{
173+
var typedObject = (Tenant)anotherObject;
174+
equalObjects =
175+
this.TenantId.Equals(typedObject.TenantId) &&
176+
this.Name.Equals(typedObject.Name);
177+
}
178+
return equalObjects;
179+
}
180+
181+
public override int GetHashCode()
182+
{
183+
return
184+
+(48123 * 257)
185+
+ this.TenantId.GetHashCode()
186+
+ this.Name.GetHashCode();
187+
}
188+
189+
public override string ToString()
190+
{
191+
return "Tenant ["
192+
+ ", tenantId=" + TenantId
193+
+ ", name=" + Name
194+
+ ", description=" + Description
195+
+ ", active=" + Active
196+
+ "]";
197+
}
198+
}
199+
}

‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/TenantEvents.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
1717
using System;
1818
using SaaSOvation.Common.Domain.Model;
1919

20-
public class TenantAdministratorRegistered : DomainEvent
20+
public class TenantAdministratorRegistered : IDomainEvent
2121
{
2222
public TenantAdministratorRegistered(
2323
TenantId tenantId,
@@ -48,7 +48,7 @@ public TenantAdministratorRegistered(
4848
public string TenantId { get; private set; }
4949
}
5050

51-
public class GroupProvisioned : DomainEvent
51+
public class GroupProvisioned : IDomainEvent
5252
{
5353
public GroupProvisioned(TenantId tenantId, string name)
5454
{
@@ -67,7 +67,7 @@ public GroupProvisioned(TenantId tenantId, string name)
6767
public string TenantId { get; private set; }
6868
}
6969

70-
public class TenantActivated : DomainEvent
70+
public class TenantActivated : IDomainEvent
7171
{
7272
public TenantActivated(TenantId tenantId)
7373
{
@@ -83,7 +83,7 @@ public TenantActivated(TenantId tenantId)
8383
public string TenantId { get; private set; }
8484
}
8585

86-
public class TenantDeactivated : DomainEvent
86+
public class TenantDeactivated : IDomainEvent
8787
{
8888
public TenantDeactivated(TenantId tenantId)
8989
{
@@ -99,7 +99,7 @@ public TenantDeactivated(TenantId tenantId)
9999
public string TenantId { get; private set; }
100100
}
101101

102-
public class TenantProvisioned : DomainEvent
102+
public class TenantProvisioned : IDomainEvent
103103
{
104104
public TenantProvisioned(TenantId tenantId)
105105
{
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,102 @@
1-
// Copyright 2012,2013 Vaughn Vernon
2-
//
3-
// Licensed under the Apache License, Version 2.0 (the "License");
4-
// you may not use this file except in compliance with the License.
5-
// You may obtain a copy of the License at
6-
//
7-
// http://www.apache.org/licenses/LICENSE-2.0
8-
//
9-
// Unless required by applicable law or agreed to in writing, software
10-
// distributed under the License is distributed on an "AS IS" BASIS,
11-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12-
// See the License for the specific language governing permissions and
13-
// limitations under the License.
14-
15-
namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
16-
{
17-
using System;
18-
using SaaSOvation.Common.Domain.Model;
19-
using SaaSOvation.IdentityAccess.Domain.Model.Access;
20-
21-
public class TenantProvisioningService
22-
{
23-
public TenantProvisioningService(
24-
TenantRepository tenantRepository,
25-
UserRepository userRepository,
26-
RoleRepository roleRepository)
27-
{
28-
this.roleRepository = roleRepository;
29-
this.tenantRepository = tenantRepository;
30-
this.userRepository = userRepository;
31-
}
32-
33-
readonly RoleRepository roleRepository;
34-
readonly TenantRepository tenantRepository;
35-
readonly UserRepository userRepository;
36-
37-
public Tenant ProvisionTenant(
38-
String tenantName,
39-
String tenantDescription,
40-
FullName administorName,
41-
EmailAddress emailAddress,
42-
PostalAddress postalAddress,
43-
Telephone primaryTelephone,
44-
Telephone secondaryTelephone)
45-
{
46-
try
47-
{
48-
// must be active to register admin
49-
var tenant = new Tenant(tenantName, tenantDescription, true);
50-
51-
this.tenantRepository.Add(tenant);
52-
53-
RegisterAdministratorFor(tenant, administorName, emailAddress, postalAddress, primaryTelephone, secondaryTelephone);
54-
55-
DomainEventPublisher.Instance.Publish(new TenantProvisioned(tenant.TenantId));
56-
57-
return tenant;
58-
59-
}
60-
catch (Exception e)
61-
{
62-
throw new InvalidOperationException(
63-
"Cannot provision tenant because: "
64-
+ e.Message);
65-
}
66-
}
67-
68-
void RegisterAdministratorFor(Tenant tenant, FullName administorName, EmailAddress emailAddress, PostalAddress postalAddress, Telephone primaryTelephone, Telephone secondaryTelephone)
69-
{
70-
var invitation = tenant.OfferRegistrationInvitation("init").OpenEnded();
71-
72-
var strongPassword = new PasswordService().GenerateStrongPassword();
73-
74-
var admin =
75-
tenant.RegisterUser(
76-
invitation.InvitationId,
77-
"admin",
78-
strongPassword,
79-
Enablement.IndefiniteEnablement(),
80-
new Person(
81-
tenant.TenantId,
82-
administorName,
83-
new ContactInformation(
84-
emailAddress,
85-
postalAddress,
86-
primaryTelephone,
87-
secondaryTelephone)));
88-
89-
tenant.WithdrawInvitation(invitation.InvitationId);
90-
91-
this.userRepository.Add(admin);
92-
93-
var adminRole = tenant.ProvisionRole("Administrator", "Default " + tenant.Name + " administrator.");
94-
95-
adminRole.AssignUser(admin);
96-
97-
this.roleRepository.Add(adminRole);
98-
99-
DomainEventPublisher.Instance.Publish(new TenantAdministratorRegistered(tenant.TenantId, tenant.Name, administorName, emailAddress, admin.Username, strongPassword));
100-
}
101-
}
102-
}
1+
// Copyright 2012,2013 Vaughn Vernon
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
16+
{
17+
using System;
18+
using SaaSOvation.Common.Domain.Model;
19+
using SaaSOvation.IdentityAccess.Domain.Model.Access;
20+
21+
public class TenantProvisioningService
22+
{
23+
public TenantProvisioningService(
24+
ITenantRepository tenantRepository,
25+
IUserRepository userRepository,
26+
IRoleRepository roleRepository)
27+
{
28+
this.roleRepository = roleRepository;
29+
this.tenantRepository = tenantRepository;
30+
this.userRepository = userRepository;
31+
}
32+
33+
readonly IRoleRepository roleRepository;
34+
readonly ITenantRepository tenantRepository;
35+
readonly IUserRepository userRepository;
36+
37+
public Tenant ProvisionTenant(
38+
String tenantName,
39+
String tenantDescription,
40+
FullName administorName,
41+
EmailAddress emailAddress,
42+
PostalAddress postalAddress,
43+
Telephone primaryTelephone,
44+
Telephone secondaryTelephone)
45+
{
46+
try
47+
{
48+
// must be active to register admin
49+
var tenant = new Tenant(tenantName, tenantDescription, true);
50+
51+
this.tenantRepository.Add(tenant);
52+
53+
RegisterAdministratorFor(tenant, administorName, emailAddress, postalAddress, primaryTelephone, secondaryTelephone);
54+
55+
DomainEventPublisher.Instance.Publish(new TenantProvisioned(tenant.TenantId));
56+
57+
return tenant;
58+
59+
}
60+
catch (Exception e)
61+
{
62+
throw new InvalidOperationException(
63+
"Cannot provision tenant because: "
64+
+ e.Message);
65+
}
66+
}
67+
68+
void RegisterAdministratorFor(Tenant tenant, FullName administorName, EmailAddress emailAddress, PostalAddress postalAddress, Telephone primaryTelephone, Telephone secondaryTelephone)
69+
{
70+
var invitation = tenant.OfferRegistrationInvitation("init").OpenEnded();
71+
72+
var strongPassword = new PasswordService().GenerateStrongPassword();
73+
74+
var admin =
75+
tenant.RegisterUser(
76+
invitation.InvitationId,
77+
"admin",
78+
strongPassword,
79+
Enablement.IndefiniteEnablement(),
80+
new Person(
81+
tenant.TenantId,
82+
administorName,
83+
new ContactInformation(
84+
emailAddress,
85+
postalAddress,
86+
primaryTelephone,
87+
secondaryTelephone)));
88+
89+
tenant.WithdrawInvitation(invitation.InvitationId);
90+
91+
this.userRepository.Add(admin);
92+
93+
var adminRole = tenant.ProvisionRole("Administrator", "Default " + tenant.Name + " administrator.");
94+
95+
adminRole.AssignUser(admin);
96+
97+
this.roleRepository.Add(adminRole);
98+
99+
DomainEventPublisher.Instance.Publish(new TenantAdministratorRegistered(tenant.TenantId, tenant.Name, administorName, emailAddress, admin.Username, strongPassword));
100+
}
101+
}
102+
}

‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model.Identity/UserEvents.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace SaaSOvation.IdentityAccess.Domain.Model.Identity
1717
using System;
1818
using SaaSOvation.Common.Domain.Model;
1919

20-
public class PersonContactInformationChanged : DomainEvent
20+
public class PersonContactInformationChanged : IDomainEvent
2121
{
2222
public PersonContactInformationChanged(
2323
TenantId tenantId,
@@ -42,7 +42,7 @@ public PersonContactInformationChanged(
4242
public string Username { get; private set; }
4343
}
4444

45-
public class PersonNameChanged : DomainEvent
45+
public class PersonNameChanged : IDomainEvent
4646
{
4747
public PersonNameChanged(
4848
TenantId tenantId,
@@ -67,7 +67,7 @@ public PersonNameChanged(
6767
public string Username { get; private set; }
6868
}
6969

70-
public class UserEnablementChanged : DomainEvent
70+
public class UserEnablementChanged : IDomainEvent
7171
{
7272
public UserEnablementChanged(
7373
TenantId tenantId,
@@ -92,7 +92,7 @@ public UserEnablementChanged(
9292
public string Username { get; private set; }
9393
}
9494

95-
public class UserPasswordChanged : DomainEvent
95+
public class UserPasswordChanged : IDomainEvent
9696
{
9797
public UserPasswordChanged(
9898
TenantId tenantId,
@@ -113,7 +113,7 @@ public UserPasswordChanged(
113113
public string Username { get; private set; }
114114
}
115115

116-
public class UserRegistered : DomainEvent
116+
public class UserRegistered : IDomainEvent
117117
{
118118
public UserRegistered(
119119
TenantId tenantId,

‎iddd_identityaccess/SaaSOvation.IdentityAccess.Domain.Model/DomainRegistry.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace SaaSOvation.IdentityAccess.Domain.Model
2020

2121
public class DomainRegistry
2222
{
23-
public static EncryptionService EncryptionService
23+
public static IEncryptionService EncryptionService
2424
{
2525
get
2626
{
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,43 @@
1-
// Copyright 2012,2013 Vaughn Vernon
2-
//
3-
// Licensed under the Apache License, Version 2.0 (the "License");
4-
// you may not use this file except in compliance with the License.
5-
// You may obtain a copy of the License at
6-
//
7-
// http://www.apache.org/licenses/LICENSE-2.0
8-
//
9-
// Unless required by applicable law or agreed to in writing, software
10-
// distributed under the License is distributed on an "AS IS" BASIS,
11-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12-
// See the License for the specific language governing permissions and
13-
// limitations under the License.
14-
15-
namespace SaaSOvation.IdentityAccess.Port.Adapter.Security
16-
{
17-
using System;
18-
using System.Security.Cryptography;
19-
using System.Text;
20-
using SaaSOvation.IdentityAccess.Domain.Model.Identity;
21-
using SaaSOvation.Common.Domain.Model;
22-
23-
public class MD5EncryptionService : EncryptionService
24-
{
25-
public string EncryptedValue(string plainTextValue)
26-
{
27-
AssertionConcern.AssertArgumentNotEmpty(plainTextValue, "Plain text value to encrypt must be provided.");
28-
29-
var encryptedValue = new StringBuilder();
30-
31-
var hasher = MD5.Create();
32-
33-
var data = hasher.ComputeHash(Encoding.Default.GetBytes(plainTextValue));
34-
35-
for (int dataIndex = 0; dataIndex < data.Length; dataIndex++)
36-
{
37-
encryptedValue.Append(data[dataIndex].ToString("x2"));
38-
}
39-
40-
return encryptedValue.ToString();
41-
}
42-
}
43-
}
1+
// Copyright 2012,2013 Vaughn Vernon
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace SaaSOvation.IdentityAccess.Port.Adapter.Security
16+
{
17+
using System;
18+
using System.Security.Cryptography;
19+
using System.Text;
20+
using SaaSOvation.IdentityAccess.Domain.Model.Identity;
21+
using SaaSOvation.Common.Domain.Model;
22+
23+
public class MD5EncryptionService : IEncryptionService
24+
{
25+
public string EncryptedValue(string plainTextValue)
26+
{
27+
AssertionConcern.AssertArgumentNotEmpty(plainTextValue, "Plain text value to encrypt must be provided.");
28+
29+
var encryptedValue = new StringBuilder();
30+
31+
var hasher = MD5.Create();
32+
33+
var data = hasher.ComputeHash(Encoding.Default.GetBytes(plainTextValue));
34+
35+
for (int dataIndex = 0; dataIndex < data.Length; dataIndex++)
36+
{
37+
encryptedValue.Append(data[dataIndex].ToString("x2"));
38+
}
39+
40+
return encryptedValue.ToString();
41+
}
42+
}
43+
}

‎iddd_identityaccess/iddd_identityaccess.csproj

+5-5
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,17 @@
4343
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Access\AuthorizationService.cs" />
4444
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Access\Role.cs" />
4545
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Access\RoleEvents.cs" />
46-
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Access\RoleRepository.cs" />
46+
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Access\IRoleRepository.cs" />
4747
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\AuthenticationService.cs" />
4848
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\ContactInformation.cs" />
4949
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\Enablement.cs" />
50-
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\EncryptionService.cs" />
50+
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\IEncryptionService.cs" />
5151
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\FullName.cs" />
5252
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\Group.cs" />
5353
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\GroupEvents.cs" />
5454
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\GroupMember.cs" />
5555
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\GroupMemberService.cs" />
56-
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\GroupRepository.cs" />
56+
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\IGroupRepository.cs" />
5757
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\InvitationDescriptor.cs" />
5858
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\PasswordService.cs" />
5959
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\Person.cs" />
@@ -62,11 +62,11 @@
6262
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\TenantEvents.cs" />
6363
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\TenantId.cs" />
6464
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\TenantProvisioningService.cs" />
65-
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\TenantRepository.cs" />
65+
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\ITenantRepository.cs" />
6666
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\User.cs" />
6767
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\UserDescriptor.cs" />
6868
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\UserEvents.cs" />
69-
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\UserRepository.cs" />
69+
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model.Identity\IUserRepository.cs" />
7070
<Compile Include="Properties\AssemblyInfo.cs" />
7171
<Compile Include="SaaSOvation.IdentityAccess.Domain.Model\DomainRegistry.cs" />
7272
<Compile Include="SaaSOvation.IdentityAccess.Port.Adapter.Security\MD5EncryptionService.cs" />

0 commit comments

Comments
 (0)
Please sign in to comment.