Skip to content

Commit b2b13fa

Browse files
RyanmeakinsRyanECharity Marani
authored
Endpoint fixes (#30)
* Adds returning of sample resource types from the endpoint * Adds sample schema types support * fix: Make schema discovery response SCIM compliant - Fix type property's value in atttributes schema to be camelCase - Add subAttributes to complex types - Add schemas attribute to Schema resource - Remove all unused imports - Put all using statements inside namespace - Fix typos in the code - Use expression body where necessary - Add Authentication Co-authored-by: RyanE <[email protected]> Co-authored-by: Charity Marani <[email protected]>
1 parent ae181c1 commit b2b13fa

29 files changed

+1701
-80
lines changed

Microsoft.SCIM.WebHostSample/Provider/InMemoryProvider.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,45 @@
33
namespace Microsoft.SCIM.WebHostSample.Provider
44
{
55
using System;
6+
using System.Collections.Generic;
67
using System.Threading.Tasks;
78
using Microsoft.SCIM;
9+
using Microsoft.SCIM.WebHostSample.Resources;
810

911
public class InMemoryProvider : ProviderBase
1012
{
1113
private readonly ProviderBase groupProvider;
1214
private readonly ProviderBase userProvider;
1315

16+
private static readonly Lazy<IReadOnlyCollection<TypeScheme>> TypeSchema =
17+
new Lazy<IReadOnlyCollection<TypeScheme>>(
18+
() =>
19+
new TypeScheme[]
20+
{
21+
SampleTypeScheme.UserTypeScheme,
22+
SampleTypeScheme.GroupTypeScheme,
23+
SampleTypeScheme.EnterpriseUserTypeScheme,
24+
SampleTypeScheme.ResourceTypesTypeScheme,
25+
SampleTypeScheme.SchemaTypeScheme,
26+
SampleTypeScheme.ServiceProviderConfigTypeScheme
27+
});
28+
29+
private static readonly Lazy<IReadOnlyCollection<Core2ResourceType>> Types =
30+
new Lazy<IReadOnlyCollection<Core2ResourceType>>(
31+
() =>
32+
new Core2ResourceType[] { SampleResourceTypes.UserResourceType, SampleResourceTypes.GroupResourceType } );
33+
34+
1435
public InMemoryProvider()
1536
{
1637
this.groupProvider = new InMemoryGroupProvider();
1738
this.userProvider = new InMemoryUserProvider();
1839
}
1940

41+
public override IReadOnlyCollection<Core2ResourceType> ResourceTypes => InMemoryProvider.Types.Value;
42+
43+
public override IReadOnlyCollection<TypeScheme> Schema => InMemoryProvider.TypeSchema.Value;
44+
2045
public override Task<Resource> CreateAsync(Resource resource, string correlationIdentifier)
2146
{
2247
if (resource is Core2EnterpriseUser)

Microsoft.SCIM.WebHostSample/Provider/InMemoryStorage.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,7 @@ private InMemoryStorage()
2222
() =>
2323
new InMemoryStorage());
2424

25-
public static InMemoryStorage Instance
26-
{
27-
get
28-
{
29-
return InMemoryStorage.InstanceValue.Value;
30-
}
31-
}
25+
public static InMemoryStorage Instance => InMemoryStorage.InstanceValue.Value;
26+
3227
}
3328
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) Microsoft Corporation.// Licensed under the MIT license.
2+
3+
namespace Microsoft.SCIM.WebHostSample.Resources
4+
{
5+
public static class SampleAddressesAttribute
6+
{
7+
public static AttributeScheme FormattedAddressAttributeScheme
8+
{
9+
get
10+
{
11+
AttributeScheme formattedAddressScheme = new AttributeScheme("formatted", AttributeDataType.@string, false)
12+
{
13+
Description = SampleConstants.DescriptionFormattedAddress
14+
};
15+
return formattedAddressScheme;
16+
17+
}
18+
}
19+
public static AttributeScheme StreetAddressAttributeScheme
20+
{
21+
get
22+
{
23+
AttributeScheme streetAddressScheme = new AttributeScheme("streetAddress", AttributeDataType.@string, false)
24+
{
25+
Description = SampleConstants.DescriptionStreetAddress
26+
};
27+
return streetAddressScheme;
28+
29+
}
30+
}
31+
32+
public static AttributeScheme CountryAddressAttributeScheme
33+
{
34+
get
35+
{
36+
AttributeScheme countryAddressScheme = new AttributeScheme("country", AttributeDataType.@string, false)
37+
{
38+
Description = SampleConstants.DescriptionAddressCountry
39+
};
40+
return countryAddressScheme;
41+
}
42+
}
43+
44+
public static AttributeScheme LocalityAddressAttributeScheme
45+
{
46+
get
47+
{
48+
AttributeScheme localityAddressScheme = new AttributeScheme("locality", AttributeDataType.@string, false)
49+
{
50+
Description = SampleConstants.DescriptionAddressLocality
51+
};
52+
return localityAddressScheme;
53+
}
54+
}
55+
56+
public static AttributeScheme PostalCodeAddressAttributeScheme
57+
{
58+
get
59+
{
60+
AttributeScheme postalCodeAddressScheme = new AttributeScheme("postalCode", AttributeDataType.@string, false)
61+
{
62+
Description = SampleConstants.DescriptionAddressPostalCode
63+
};
64+
return postalCodeAddressScheme;
65+
}
66+
}
67+
68+
public static AttributeScheme RegionAddressAttributeScheme
69+
{
70+
get
71+
{
72+
AttributeScheme regionAddressScheme = new AttributeScheme("region", AttributeDataType.@string, false)
73+
{
74+
Description = SampleConstants.DescriptionAddressRegion
75+
};
76+
return regionAddressScheme;
77+
}
78+
}
79+
}
80+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) Microsoft Corporation.// Licensed under the MIT license.
2+
3+
namespace Microsoft.SCIM.WebHostSample.Resources
4+
{
5+
public static class SampleCommonAttributes
6+
{
7+
public static AttributeScheme IdentiFierAttributeScheme
8+
{
9+
get
10+
{
11+
AttributeScheme idScheme = new AttributeScheme("id", AttributeDataType.@string, false)
12+
{
13+
Description = SampleConstants.DescriptionIdentifier
14+
};
15+
return idScheme;
16+
}
17+
}
18+
}
19+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright (c) Microsoft Corporation.// Licensed under the MIT license.
2+
3+
namespace Microsoft.SCIM.WebHostSample.Resources
4+
{
5+
public class SampleConstants
6+
{
7+
public const string Core2SchemaPrefix = "urn:ietf:params:scim:schemas:core:2.0:";
8+
public const string UserAccount = "User Account";
9+
public const string ServiceProviderConfig = "Service Provider Configuration";
10+
public const string UserEnterprise = "Enterprise User";
11+
public const string UserEnterpriseName = "EnterpriseUser";
12+
public const string UserEnterpriseSchema = "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User";
13+
public const string DescriptionResourceTypeSchema = "Specifies the schema that describes a SCIM resource type";
14+
public const string DescriptionActive = "A Boolean value indicating the User's administrative status.";
15+
public const string DescriptionAddresses = "A physical mailing address for this User. Canonical type" +
16+
" values of \"work\", \"home\", and \"other\". This attribute is a complex type with the following sub-attributes.";
17+
public const string DescriptionCostCenter = "Identifies the name of a cost center.";
18+
public const string DescriptionDisplayName = "The name of the User, suitable for display to end-users. " +
19+
"The name SHOULD be the full name of the User being described, if known.";
20+
public const string DescriptionDivision = "Identifies the name of a division.";
21+
public const string Descriptiondepartment = "Identifies the name of a department.";
22+
public const string DescriptionEmails = "Email addresses for the user. The value SHOULD be canonicalized by " +
23+
"the service provider, e.g., \"[email protected]\" instead of \"[email protected]\". Canonical type values " +
24+
"of \"work\", \"home\", and \"other\".";
25+
public const string DescriptionEmployeeNumber = "Numeric or alphanumeric identifier assigned to a person, " +
26+
"typically based on order of hire or association with an organization.";
27+
public const string DescriptionGroupDisplayName = "A human-readable name for the Group. REQUIRED.";
28+
public const string DescriptionLocale = "Used to indicate the User's default location for purposes of localizing" +
29+
" items such as currency, date time format, or numerical representations.";
30+
public const string DescriptionManager = "The User's manager. A complex type that optionally allows " +
31+
"service providers to represent organizational hierarchy by referencing the \"id\" attribute of another User.";
32+
public const string DescriptionMemebers = "A list of members of the Group.";
33+
public const string DescriptionName = "The components of the user's real name. Providers MAY return just " +
34+
"the full name as a single string in the formatted sub-attribute, or they MAY return just the " +
35+
"individual component attributes using the other sub-attributes, or they MAY return both. " +
36+
"If both variants are returned, they SHOULD be describing the same name, with the formatted name " +
37+
"indicating how the component attributes should be combined.";
38+
public const string DescriptionOrganization = "Identifies the name of an organization.";
39+
public const string DescriptionPhoneNumbers = "Phone numbers for the User. The value SHOULD be canonicalized" +
40+
" by the service provider according to the format specified in RFC 3966, e.g., \"tel:+1-201-555-0123\". " +
41+
"Canonical type values of \"work\", \"home\", \"mobile\", \"fax\", \"pager\", and \"other\".";
42+
public const string DescriptionPreferredLanguage = "Indicates the User's preferred written or spoken language. " +
43+
"Generally used for selecting a localized user interface; e.g., \"en_US\" specifies the language English and country US.";
44+
public const string DescriptionTitle = "The user's title, such as \"Vice President.\"";
45+
public const string DescriptionUserName = "Unique identifier for the User, typically used by the user to " +
46+
"directly authenticate to the service provider. Each User MUST include a non-empty userName value. " +
47+
"This identifier MUST be unique across the service provider's entire set of Users. REQUIRED.";
48+
public const string DescriptionUserType = "Used to identify the relationship between the organization and the user. " +
49+
"Typical values used might be \"Contractor\", \"Employee\", \"Intern\", \"Temp\", \"External\", and \"Unknown\", " +
50+
"but any value may be used.";
51+
public const string DescriptionValue = "The significant value for the attribute";
52+
public const string DescriptionType = "A label indicating the attribute's function";
53+
public const string DescriptionFormattedName = "The full name, including all middle " +
54+
"names, titles, and suffixes as appropriate, formatted for display e.g., 'Ms. Barbara J Jensen, III').";
55+
public const string DescriptionGivenName = "The given name of the User, or" +
56+
" first name in most Western languages(e.g., 'Barbara' given the full name 'Ms. Barbara J Jensen, III').";
57+
public const string DescriptionDisplay = "A human-readable name, primarily used for display purposes.READ-ONLY.";
58+
public const string DescriptionPrimary = "A Boolean value indicating the 'primary' " + " or preferred attribute value for this attribute, " +
59+
"The primary attribute value 'true' MUST appear no more than once.";
60+
public const string DescriptionStreetAddress = "The full street address component, which may include house number, street name, P.O.box, and multi-line" +
61+
"extended street address information.This attribute MAY contain newlines.";
62+
public const string DescriptionFormattedAddress = "The full mailing address, formatted for display or use with a mailing label." +
63+
" This attribute MAY contain newlines.";
64+
public const string DescriptionFamilyName = "The family name of the User, or last name in most Western languages(e.g., 'Jensen' given the full " +
65+
"name 'Ms. Barbara J Jensen, III').";
66+
public const string DescriptionHonorificPrefix = "The honorific prefix(es) of the User, or title in most Western languages(e.g., 'Ms.' " +
67+
"given the full name 'Ms. Barbara J Jensen, III').";
68+
public const string DescriptionHonorificSuffix = "The honorific suffix(es) of the User, or suffix in most Western languages(e.g., 'III' " +
69+
"given the full name 'Ms. Barbara J Jensen, III').";
70+
public const string DescriptionNickName = "The casual way to address the user in real life, e.g., 'Bob' or 'Bobby' instead of 'Robert'. " +
71+
"This attribute SHOULD NOT be used to represent a User's username (e.g., 'bjensen' or 'mpepperidge').";
72+
public const string DescriptionTimeZone = "The User's time zone in the 'Olson' time zone database format, e.g., 'America/Los_Angeles'.";
73+
public const string DescriptionPassword = "The User's cleartext password. This attribute is intended to be used as a means to specify an initial " +
74+
"password when creating a new User or to reset an existing User's password.";
75+
public const string DescriptionIms = "Instant messaging addresses for the User.";
76+
public const string DescriptionRoles = "A list of roles for the User that collectively represent who the User is, e.g., 'Student', 'Faculty'.";
77+
public const string DescriptionIdentifier = "The server unique id of a SCIM resource";
78+
public const string DescriptionResourceTypeName = "The resource type name. When applicable,service providers MUST specify the name, e.g., 'User'.";
79+
public const string DescriptionResourceTypeEndpoint = "The resource type's HTTP-addressable endpoint relative to the Base URL, e.g., '/Users'.";
80+
public const string DescriptionResourceTypeSchemaAttribute = "The resource type's primary/base schema URI.";
81+
public const string DescriptionScimSchema = "Specifies the schema that describes a SCIM schema";
82+
public const string DescriptionSchemaName = "The schema's human-readable name. When applicable, service providers MUST specify the name, e.g., 'User'.";
83+
public const string DescriptionSchemaAttributes = "A complex attribute that includes the attributes of a schema.";
84+
public const string DescriptionAttributeName = "The attribute's name.";
85+
public const string DescriptionAttributeType = "The attribute's data type. Valid values include 'string', 'complex', 'boolean', 'decimal', 'integer', 'dateTime', 'reference'.";
86+
public const string DescriptionAttributeMultiValued = "A Boolean value indicating an attribute's plurality.";
87+
public const string DescriptionAttributeDescription = "A human-readable description of the attribute.";
88+
public const string DescriptionAttributeRequired = "A boolean value indicating whether or not the attribute is required.";
89+
public const string DescriptionAttributeCanonicalValues = "A collection of canonical values. When applicable, service providers MUST specify the canonical types, e.g., 'work', 'home'.";
90+
public const string DescriptionAttributeCaseExact = "A Boolean value indicating whether or not a string attribute is case sensitive.";
91+
public const string DescriptionAttributeMutability = "Indicates whether or not an attribute is modifiable.";
92+
public const string DescriptionAttributeReturned = "Indicates when an attribute is returned in a response(e.g., to a query).";
93+
public const string DescriptionAttributeUniqueness = "Indicates how unique a value must be.";
94+
public const string DescriptionAttributeReferenceTypes = "Used only with an attribute of type 'reference'. Specifies a SCIM resourceType that a reference attribute MAY refer to, e.g., 'User'.";
95+
public const string DescriptionAttributeSubAttributes = "Used to define the sub-attributes of a complex attribute.";
96+
public const string DescriptionServiceProviderConfigSchema = "Schema for representing the service provider's configuration";
97+
public const string DescriptionServiceProviderConfigDocumentationUri = "An HTTP-addressable URL pointing to the service provider's human-consumable help documentation.";
98+
public const string DescriptionServiceProviderConfigPatch = "A complex type that specifies PATCH configuration options.";
99+
public const string DescriptionServiceProviderConfigSupported = "A Boolean value specifying whether or not the operation is supported.";
100+
public const string DescriptionServiceProviderConfigBulk = "A complex type that specifies bulk configuration options.";
101+
public const string DescriptionServiceProviderConfigEtag = "A complex type that specifies ETag configuration options.REQUIRED.";
102+
public const string DescriptionServiceProviderConfigBulkMaxOperations = "An integer value specifying the maximum number of operations.";
103+
public const string DescriptionServiceProviderConfigBulkMaxPayloadSize = "An integer value specifying the maximum payload size in bytes.";
104+
public const string DescriptionServiceProviderConfigFilter = "A complex type that specifies FILTER options.";
105+
public const string DescriptionServiceProviderConfigFilterMaxResults = "An integer value specifying the maximum number of resources returned in a response.";
106+
public const string DescriptionServiceProviderConfigChangePassword = "A complex type that specifies configuration options related to changing a password.";
107+
public const string DescriptionServiceProviderConfigSort = "A complex type that specifies sort result options.";
108+
public const string DescriptionServiceProviderAuthenticationSchemes = "A complex type that specifies supported authentication scheme properties.";
109+
public const string DescriptionServiceProviderAuthenticationSchemesName = "The common authentication scheme name, e.g., HTTP Basic.";
110+
public const string DescriptionServiceProviderAuthenticationSchemesDescription = "A description of the authentication scheme.";
111+
public const string DescriptionServiceProviderAuthenticationSchemesSpecUri = "An HTTP-addressable URL pointing to the authentication scheme's specification.";
112+
public const string DescriptionServiceProviderAuthenticationSchemesDocumentationUri = "An HTTP-addressable URL pointing to the authentication scheme's usage documentation.";
113+
public const string DescriptionAddressCountry = "The country name component.";
114+
public const string DescriptionAddressLocality = "The city or locality component.";
115+
public const string DescriptionAddressPostalCode = "The country name component.";
116+
public const string DescriptionAddressRegion = "The state or region component.";
117+
public const string DescriptionAddressType = "A label indicating the attribute's function, e.g., 'work' or 'home'.";
118+
public const string SampleScimEndpoint = "http://localhost:5000/scim";
119+
}
120+
}

0 commit comments

Comments
 (0)