This commit is contained in:
Sam Xu 2019-06-26 17:35:48 -07:00
parent f6470b0df7
commit 4d8264dfb1
15 changed files with 745 additions and 276 deletions

View file

@ -24,6 +24,20 @@ namespace Microsoft.OpenApi.OData.Edm
private static IEdmModel _savedModel = null; // if diffenent model, the cache will be cleaned.
private static object _objectLock = new object();
/// <summary>
/// Get the term qualified name when using the type of <typeparamref name="T"/>
/// </summary>
/// <typeparam name="T">The type of the term.</typeparam>
/// <returns>The qualified name.</returns>
public static string GetTermQualifiedName<T>()
{
object[] attributes = typeof(T).GetCustomAttributes(typeof(TermAttribute), false);
Debug.Assert(attributes != null && attributes.Length == 1);
TermAttribute term = (TermAttribute)attributes[0];
return term.QualifiedName;
}
/// <summary>
/// Gets the boolean term value for the given <see cref="IEdmVocabularyAnnotatable"/>.
/// </summary>
@ -199,6 +213,23 @@ namespace Microsoft.OpenApi.OData.Edm
});
}
/// <summary>
/// Gets the collection of record value (a complex type) for the given <see cref="IEdmVocabularyAnnotatable"/>.
/// </summary>
/// <typeparam name="T">The CLR mapping type.</typeparam>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm target.</param>
/// <returns>Null or the colllection of record value (a complex type) for this annotation.</returns>
public static IEnumerable<T> GetCollection<T>(this IEdmModel model, IEdmVocabularyAnnotatable target)
where T : IRecord, new()
{
Utils.CheckArgumentNull(model, nameof(model));
Utils.CheckArgumentNull(target, nameof(target));
string qualifiedName = GetTermQualifiedName<T>();
return GetCollection<T>(model, target, qualifiedName);
}
/// <summary>
/// Gets the collection of record value (a complex type) for the given <see cref="IEdmVocabularyAnnotatable"/>.
/// </summary>
@ -449,14 +480,7 @@ namespace Microsoft.OpenApi.OData.Edm
return null;
}
private static string GetTermQualifiedName<T>()
{
object[] attributes = typeof(T).GetCustomAttributes(typeof(TermAttribute), false);
Debug.Assert(attributes != null && attributes.Length == 1);
TermAttribute term = (TermAttribute)attributes[0];
return term.QualifiedName;
}
private static Type GetTypeInfo<T>(string fullTypeName) where T : IRecord
{

View file

@ -6,13 +6,11 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
using Microsoft.OpenApi.OData.Operation;
using Microsoft.OpenApi.OData.PathItem;
using Microsoft.OpenApi.OData.Vocabulary.Authorization;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
namespace Microsoft.OpenApi.OData.Edm
@ -24,7 +22,6 @@ namespace Microsoft.OpenApi.OData.Edm
{
private IEnumerable<ODataPath> _allPaths;
private IODataPathProvider _pathProvider;
private AuthorizationProvider _authorizationProvider;
/// <summary>
/// Initializes a new instance of <see cref="ODataContext"/> class.
@ -52,7 +49,6 @@ namespace Microsoft.OpenApi.OData.Edm
OperationHanderProvider = new OperationHandlerProvider();
PathItemHanderProvider = new PathItemHandlerProvider();
_authorizationProvider = new AuthorizationProvider(model);
_pathProvider = new ODataPathProvider();
if (settings.EnableKeyAsSegment != null)
@ -136,16 +132,6 @@ namespace Microsoft.OpenApi.OData.Edm
/// </summary>
public IList<OpenApiTag> Tags { get; private set; }
/// <summary>
/// Gets the <see cref="Authorization"/> collections for a given target in the given Edm model.
/// </summary>
/// <param name="target">The Edm target.</param>
/// <returns>The <see cref="Authorization"/> collections.</returns>
public IEnumerable<Authorization> GetAuthorizations(IEdmVocabularyAnnotatable target)
{
return _authorizationProvider?.GetAuthorizations(target);
}
/// <summary>
/// Append tag.
/// </summary>

View file

@ -18,11 +18,6 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Authorization
/// Abstract complex type: 'Org.OData.Authorization.V1.Authorization'
/// </summary>
[Term("Org.OData.Authorization.Authorizations")]
[SubType(AuthorizationConstants.OpenIDConnect, typeof(OpenIDConnect))]
[SubType(AuthorizationConstants.Http, typeof(Http))]
[SubType(AuthorizationConstants.ApiKey, typeof(ApiKey))]
[SubType(AuthorizationConstants.OAuth2ClientCredentials, typeof(OAuth2ClientCredentials))]
internal abstract class Authorization : IRecord
{
/// <summary>
@ -73,7 +68,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Authorization
return null;
}
Authorization auth = null;
Authorization auth;
switch (complexType.FullTypeName())
{
case AuthorizationConstants.OpenIDConnect: // OpenIDConnect

View file

@ -1,102 +0,0 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Vocabulary.Authorization
{
/// <summary>
/// The default 'Org.OData.Core.V1.Authorization' provider.
/// </summary>
internal class AuthorizationProvider
{
/// <summary>
/// Annotatable: EntitySet Singleton ActionImport FunctionImport Action Function
/// Collection(Core.HttpRequest)
/// </summary>
private IDictionary<IEdmVocabularyAnnotatable, IEnumerable<Authorization>> _authorizations
= new Dictionary<IEdmVocabularyAnnotatable, IEnumerable<Authorization>>();
/// <summary>
/// Gets the Edm model.
/// </summary>
public IEdmModel Model { get; }
/// <summary>
/// Gets the Edm Term.
/// </summary>
public IEdmTerm Term { get; }
/// <summary>
/// Initializes a new instance of <see cref="AuthorizationProvider"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
public AuthorizationProvider(IEdmModel model)
{
Utils.CheckArgumentNull(model, nameof(model));
Term = model.FindTerm(AuthorizationConstants.Authorizations);
Model = model;
}
/// <summary>
/// Gets the <see cref="Authorization"/> collections for a given target in the given Edm model.
/// </summary>
/// <param name="target">The Edm target.</param>
/// <returns>The <see cref="Authorization"/> collections.</returns>
public virtual IEnumerable<Authorization> GetAuthorizations(IEdmVocabularyAnnotatable target)
{
Utils.CheckArgumentNull(target, nameof(target));
if (_authorizations.TryGetValue(target, out IEnumerable<Authorization> value))
{
return value;
}
if (Term == null)
{
return Enumerable.Empty<Authorization>();
}
value = RetrieveAuthorizations(target);
_authorizations[target] = value;
return value;
}
/// <summary>
/// Create the corresponding Authorization object.
/// </summary>
/// <param name="record">The input record.</param>
/// <returns>The created <see cref="Authorization"/> object.</returns>
private IEnumerable<Authorization> RetrieveAuthorizations(IEdmVocabularyAnnotatable target)
{
IEdmVocabularyAnnotation annotation = Model.GetVocabularyAnnotation(target, Term);
if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.Collection)
{
IEdmCollectionExpression collection = (IEdmCollectionExpression)annotation.Value;
foreach (var item in collection.Elements)
{
IEdmRecordExpression record = item as IEdmRecordExpression;
if (record == null || record.DeclaredType == null)
{
continue;
}
Authorization auth = Authorization.CreateAuthorization(record);
if (auth != null)
{
yield return auth;
}
}
}
}
}
}

View file

@ -98,7 +98,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
// CustomHeaders
CustomHeaders = record.GetCollection<CustomParameter>("CustomHeaders");
// CustomHeaders
// CustomQueryOptions
CustomQueryOptions = record.GetCollection<CustomParameter>("CustomQueryOptions");
}
}

View file

@ -5,6 +5,7 @@
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Vocabulary.Core
{
@ -24,6 +25,16 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Core
/// <param name="record">The input record.</param>
public override void Initialize(IEdmRecordExpression record)
{
Utils.CheckArgumentNull(record, nameof(record));
/* Should we throw exception if the input record is not a primitive example value?
* Leave the below codes for further decision.
if (record.DeclaredType == null || record.DeclaredType.FullName() != "Org.OData.Core.V1.PrimitiveExampleValue")
{
throw new OpenApiException();
}
*/
// Load ExampleValue
base.Initialize(record);

View file

@ -148,7 +148,16 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests
<Singleton Name=""Me"" Type=""NS.Customer"" />
</EntityContainer>
<Annotations Target=""NS.Default/Me"">
{0}
<Annotation Term=""Org.OData.Capabilities.V1.UpdateRestrictions"">
<Record>
<PropertyValue Property=""Updatable"" Bool=""{0}"" />
</Record>
</Annotation>
<Annotation Term=""Org.OData.Capabilities.V1.afdasf"">
<Record>
<PropertyValue Property=""Updatable"" Bool=""{0}"" />
</Record>
</Annotation>
</Annotations>
</Schema>
</edmx:DataServices>

View file

@ -0,0 +1,108 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Linq;
using System.Xml.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Authorization;
using Xunit;
namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Authorization.Tests
{
public class ApiKeyTests
{
[Fact]
public void InitializeThrowArgumentNullRecord()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("record", () => new ApiKey().Initialize(record: null));
}
[Fact]
public void InitializeApiKeyWithRecordSuccess()
{
// Arrange
EdmModel model = new EdmModel();
IEdmType edmType = model.FindType("Org.OData.Authorization.V1.KeyLocation");
IEdmEnumType enumType = edmType as IEdmEnumType;
IEdmEnumMember enumMember = enumType.Members.FirstOrDefault(c => c.Name == "Header");
Assert.NotNull(enumMember);
IEdmRecordExpression record = new EdmRecordExpression(
new EdmPropertyConstructor("Name", new EdmStringConstant("DelegatedWork")),
new EdmPropertyConstructor("Description", new EdmStringConstant("Description of the authorization scheme")),
new EdmPropertyConstructor("KeyName", new EdmStringConstant("keyName")),
new EdmPropertyConstructor("Location", new EdmEnumMemberExpression(enumMember)));
ApiKey apiKey = new ApiKey();
Assert.Null(apiKey.Name);
Assert.Null(apiKey.Description);
Assert.Null(apiKey.Location);
Assert.Null(apiKey.KeyName);
// Act
apiKey.Initialize(record);
// Assert
Assert.Equal("DelegatedWork", apiKey.Name);
Assert.Equal("Description of the authorization scheme", apiKey.Description);
Assert.Equal("keyName", apiKey.KeyName);
Assert.Equal(KeyLocation.Header, apiKey.Location);
}
[Fact]
public void InitializeApiKeyWorksWithCsdl()
{
// Arrange
string annotation = @"<Annotation Term=""NS.MyApiKey"">
<Record Type=""Org.OData.Authorization.V1.ApiKey"" >
<PropertyValue Property=""Name"" String=""DelegatedWork"" />
<PropertyValue Property=""Description"" String=""Description of the authorization scheme"" />
<PropertyValue Property=""KeyName"" String=""keyName"" />
<PropertyValue Property=""Location"" EnumMember=""Org.OData.Authorization.V1.KeyLocation/QueryOption"" />
</Record>
</Annotation>";
IEdmModel model = GetEdmModel(annotation);
Assert.NotNull(model); // guard
Assert.NotNull(model.EntityContainer);
// Act
ApiKey apiKey = model.GetRecord<ApiKey>(model.EntityContainer, "NS.MyApiKey");
// Assert
Assert.NotNull(apiKey);
Assert.Equal("DelegatedWork", apiKey.Name);
Assert.Equal("Description of the authorization scheme", apiKey.Description);
Assert.Equal("keyName", apiKey.KeyName);
Assert.Equal(KeyLocation.QueryOption, apiKey.Location);
}
private IEdmModel GetEdmModel(string annotation)
{
const string template = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityContainer Name=""Container"">
{0}
</EntityContainer>
<Term Name=""MyApiKey"" Type=""Org.OData.Authorization.V1.ApiKey"" />
</Schema>
</edmx:DataServices>
</edmx:Edmx>";
string modelText = string.Format(template, annotation);
IEdmModel model;
bool result = CsdlReader.TryParse(XElement.Parse(modelText).CreateReader(), out model, out _);
Assert.True(result);
return model;
}
}
}

View file

@ -1,131 +0,0 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OData.Edm.Validation;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Authorization;
using Xunit;
namespace Microsoft.OpenApi.OData.Reader.Authorization.Tests
{
public class AuthorizationProviderTests
{
[Fact]
public void CtroThrowArgumentNullModel()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("model", () => new AuthorizationProvider(model: null));
}
[Fact]
public void GetAuthorizationsThrowArgumentNullTarget()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("target",
() => new AuthorizationProvider(EdmCoreModel.Instance).GetAuthorizations(target: null));
}
[Fact]
public void GetAuthorizationsReturnsNullForTargetWithoutAuthorization()
{
// Arrange
EdmModel model = new EdmModel();
EdmEntityContainer container = new EdmEntityContainer("NS", "Container");
model.AddElement(container);
AuthorizationProvider provider = new AuthorizationProvider(model);
// Act & Assert
var authorizations = provider.GetAuthorizations(container);
// Assert
Assert.Empty(authorizations);
}
[Theory]
[InlineData("Entities")]
[InlineData("Me")]
public void GetAuthorizationsReturnsForEdmModelNavigationSourceWithAuthroizations(string name)
{
// Arrange
IEdmModel model = GetEdmModel();
IEdmNavigationSource navigationSource = model.FindDeclaredNavigationSource(name);
Assert.NotNull(navigationSource);
AuthorizationProvider provider = new AuthorizationProvider(model);
// Act
var authorizations = model.GetAuthorizations(navigationSource as IEdmVocabularyAnnotatable);
// Assert
Assert.NotEmpty(authorizations);
Assert.Equal(2, authorizations.Count());
Assert.IsType<OpenIDConnect>(authorizations.First());
Assert.IsType<Http>(authorizations.Last());
}
private static IEdmModel GetEdmModel()
{
const string schema = @"<?xml version=""1.0"" encoding=""utf-16""?>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityType Name=""Entity"">
<Key>
<PropertyRef Name=""Id"" />
</Key>
<Property Name=""Id"" Type=""Edm.Int32"" Nullable=""false"" />
</EntityType>
<EntityContainer Name=""Container"">
<EntitySet Name=""Entities"" EntityType=""NS.Entity"">
<Annotation Term=""Org.OData.Authorization.V1.Authorizations"">
<Collection>
<Record Type=""Org.OData.Authorization.V1.OpenIDConnect"">
<PropertyValue Property=""IssuerUrl"" String=""http://any"" />
<PropertyValue Property=""Name"" String=""OpenIDConnect Name"" />
<PropertyValue Property=""Description"" String=""OpenIDConnect Description"" />
</Record>
<Record Type=""Org.OData.Authorization.V1.Http"">
<PropertyValue Property=""BearerFormat"" String=""Http BearerFormat"" />
<PropertyValue Property=""Scheme"" String=""Http Scheme"" />
<PropertyValue Property=""Name"" String=""Http Name"" />
<PropertyValue Property=""Description"" String=""Http Description"" />
</Record>
</Collection>
</Annotation>
</EntitySet>
<Singleton Name=""Me"" Type=""NS.Entity"" />
</EntityContainer>
<Annotations Target=""NS.Container/Me"">
<Annotation Term=""Org.OData.Authorization.V1.Authorizations"">
<Collection>
<Record Type=""Org.OData.Authorization.V1.OpenIDConnect"">
<PropertyValue Property=""IssuerUrl"" String=""http://any"" />
<PropertyValue Property=""Name"" String=""OpenIDConnect Name"" />
<PropertyValue Property=""Description"" String=""OpenIDConnect Description"" />
</Record>
<Record Type=""Org.OData.Authorization.V1.Http"">
<PropertyValue Property=""BearerFormat"" String=""Http BearerFormat"" />
<PropertyValue Property=""Scheme"" String=""Http Scheme"" />
<PropertyValue Property=""Name"" String=""Http Name"" />
<PropertyValue Property=""Description"" String=""Http Description"" />
</Record>
</Collection>
</Annotation>
</Annotations>
</Schema>";
IEdmModel parsedModel;
IEnumerable<EdmError> errors;
bool parsed = SchemaReader.TryParse(new XmlReader[] { XmlReader.Create(new StringReader(schema)) }, out parsedModel, out errors);
Assert.True(parsed);
return parsedModel;
}
}
}

View file

@ -0,0 +1,94 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Xml.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Authorization;
using Xunit;
namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Authorization.Tests
{
public class AuthorizationScopeTests
{
[Fact]
public void InitializeThrowArgumentNullRecord()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("record", () => new AuthorizationScope().Initialize(record: null));
}
[Fact]
public void InitializeAuthorizationScopeWithRecordSuccess()
{
// Arrange
IEdmRecordExpression record = new EdmRecordExpression(
new EdmPropertyConstructor("Scope", new EdmStringConstant("ScopeName")),
new EdmPropertyConstructor("Grant", new EdmStringConstant("GrantAccess")));
AuthorizationScope scope = new AuthorizationScope();
Assert.Null(scope.Scope);
Assert.Null(scope.Description);
Assert.Null(scope.Grant);
// Act
scope.Initialize(record);
// Assert
Assert.Equal("ScopeName", scope.Scope);
Assert.Null(scope.Description);
Assert.Equal("GrantAccess", scope.Grant);
}
[Fact]
public void InitializeAuthorizationScopeWorksWithCsdl()
{
// Arrange
string annotation = @"<Annotation Term=""NS.MyAuthorizationScope"">
<Record Type=""Org.OData.Authorization.V1.AuthorizationScope"" >
<PropertyValue Property=""Scope"" String=""Scope name"" />
<PropertyValue Property=""Description"" String=""Description of the scope"" />
<PropertyValue Property=""Grant"" String=""grant access"" />
</Record>
</Annotation>";
IEdmModel model = GetEdmModel(annotation);
Assert.NotNull(model); // guard
Assert.NotNull(model.EntityContainer);
// Act
AuthorizationScope scope = model.GetRecord<AuthorizationScope>(model.EntityContainer, "NS.MyAuthorizationScope");
// Assert
Assert.NotNull(scope);
Assert.Equal("Scope name", scope.Scope);
Assert.Equal("Description of the scope", scope.Description);
Assert.Equal("grant access", scope.Grant);
}
private IEdmModel GetEdmModel(string annotation)
{
const string template = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityContainer Name=""Container"">
{0}
</EntityContainer>
<Term Name=""MyAuthorizationScope"" Type=""Org.OData.Authorization.V1.AuthorizationScope"" />
</Schema>
</edmx:DataServices>
</edmx:Edmx>";
string modelText = string.Format(template, annotation);
IEdmModel model;
bool result = CsdlReader.TryParse(XElement.Parse(modelText).CreateReader(), out model, out _);
Assert.True(result);
return model;
}
}
}

View file

@ -0,0 +1,123 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Xml.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OpenApi.OData.Vocabulary.Authorization;
using Xunit;
namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Authorization.Tests
{
public class Authorization1Tests
{
[Fact]
public void TermAttributeAttachedOnSecurityScheme()
{
OData.Vocabulary.Authorization.Authorization a = new Http();
// Arrange & Act
string qualifiedName = EdmVocabularyAnnotationExtensions.GetTermQualifiedName<Authorization>();
// Assert
Assert.Equal("Org.OData.Authorization.V1.SecuritySchemes", qualifiedName);
}
[Fact]
public void InitializeSecuritySchemeWithRecordSuccess()
{
// Arrange
IEdmRecordExpression record = new EdmRecordExpression(
new EdmPropertyConstructor("Authorization", new EdmStringConstant("DelegatedWork")),
new EdmPropertyConstructor("RequiredScopes", new EdmCollectionExpression(
new EdmStringConstant("User.ReadAll"),
new EdmStringConstant("User.WriteAll"))));
SecurityScheme securityScheme = new SecurityScheme();
Assert.Null(securityScheme.Authorization);
Assert.Null(securityScheme.RequiredScopes);
// Act
securityScheme.Initialize(record);
// Assert
Assert.NotNull(securityScheme.Authorization);
Assert.Equal("DelegatedWork", securityScheme.Authorization);
Assert.NotNull(securityScheme.RequiredScopes);
Assert.Equal(2, securityScheme.RequiredScopes.Count);
Assert.Equal(new[] { "User.ReadAll", "User.WriteAll" }, securityScheme.RequiredScopes);
}
[Fact]
public void InitializeSecuritySchemeWorksWithCsdl()
{
// Arrange
string annotation = @"<Annotation Term=""Org.OData.Authorization.V1.SecuritySchemes"">
<Collection>
<Record>
<PropertyValue Property=""Authorization"" String=""DelegatedWork"" />
<PropertyValue Property=""RequiredScopes"" >
<Collection>
<String>User.ReadAll</String>
<String>User.WriteAll</String>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""Authorization"" String=""DelegatedPersonal"" />
<PropertyValue Property=""RequiredScopes"" >
<Collection>
<String>Directory.ReadAll</String>
<String>Directory.WriteAll</String>
</Collection>
</PropertyValue>
</Record>
</Collection>
</Annotation>";
IEdmModel model = GetEdmModel(annotation);
Assert.NotNull(model); // guard
Assert.NotNull(model.EntityContainer);
// Act
SecurityScheme[] schemes = model.GetCollection<SecurityScheme>(model.EntityContainer).ToArray();
// Assert
Assert.NotNull(schemes);
Assert.Equal(2, schemes.Length);
// #1
Assert.Equal("DelegatedWork", schemes[0].Authorization);
Assert.Equal(2, schemes[0].RequiredScopes.Count);
Assert.Equal(new[] { "User.ReadAll", "User.WriteAll" }, schemes[0].RequiredScopes);
// #2
Assert.Equal("DelegatedPersonal", schemes[1].Authorization);
Assert.Equal(2, schemes[1].RequiredScopes.Count);
Assert.Equal(new[] { "Directory.ReadAll", "Directory.WriteAll" }, schemes[1].RequiredScopes);
}
private IEdmModel GetEdmModel(string annotation)
{
const string template = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityContainer Name=""Container"">
{0}
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>";
string modelText = string.Format(template, annotation);
IEdmModel model;
bool result = CsdlReader.TryParse(XElement.Parse(modelText).CreateReader(), out model, out _);
Assert.True(result);
return model;
}
}
}

View file

@ -0,0 +1,90 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.IO;
using System.Linq;
using System.Xml;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Authorization;
using Xunit;
namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Authorization.Tests
{
public class AuthorizationVocabularyTests
{
[Fact]
public void GetAuthorizationsReturnsNullForTargetWithoutAuthorization()
{
// Arrange
EdmModel model = new EdmModel();
EdmEntityContainer container = new EdmEntityContainer("NS", "Container");
model.AddElement(container);
// Act & Assert
var authorizations = model.GetAuthorizations(container);
// Assert
Assert.Null(authorizations);
}
[Fact]
public void GetAuthorizationsReturnsForEdmModelNavigationSourceWithAuthroizations()
{
// Arrange
IEdmModel model = GetEdmModel();
Assert.NotNull(model.EntityContainer);
// Act
var authorizations = model.GetAuthorizations(model.EntityContainer);
// Assert
Assert.NotEmpty(authorizations);
Assert.Equal(2, authorizations.Count());
// #1
OpenIDConnect openID = Assert.IsType<OpenIDConnect>(authorizations.First());
Assert.Equal("OpenIDConnect Name", openID.Name);
Assert.Equal("http://any", openID.IssuerUrl);
Assert.Equal("OpenIDConnect Description", openID.Description);
// #2
Http http = Assert.IsType<Http>(authorizations.Last());
Assert.Equal("Http Name", http.Name);
Assert.Equal("Http Scheme", http.Scheme);
Assert.Equal("Http BearerFormat", http.BearerFormat);
Assert.Null(http.Description);
}
private static IEdmModel GetEdmModel()
{
const string schema = @"<?xml version=""1.0"" encoding=""utf-16""?>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityContainer Name=""Container"">
<Annotation Term=""Org.OData.Authorization.V1.Authorizations"">
<Collection>
<Record Type=""Org.OData.Authorization.V1.OpenIDConnect"">
<PropertyValue Property=""IssuerUrl"" String=""http://any"" />
<PropertyValue Property=""Name"" String=""OpenIDConnect Name"" />
<PropertyValue Property=""Description"" String=""OpenIDConnect Description"" />
</Record>
<Record Type=""Org.OData.Authorization.V1.Http"">
<PropertyValue Property=""BearerFormat"" String=""Http BearerFormat"" />
<PropertyValue Property=""Scheme"" String=""Http Scheme"" />
<PropertyValue Property=""Name"" String=""Http Name"" />
</Record>
</Collection>
</Annotation>
</EntityContainer>
</Schema>";
IEdmModel parsedModel;
bool parsed = SchemaReader.TryParse(new XmlReader[] { XmlReader.Create(new StringReader(schema)) }, out parsedModel, out _);
Assert.True(parsed);
return parsedModel;
}
}
}

View file

@ -0,0 +1,132 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Linq;
using System.Xml.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Authorization;
using Xunit;
namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Authorization.Tests
{
public class SecuritySchemeTests
{
[Fact]
public void InitializeThrowArgumentNullRecord()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentNullException>("record", () => new SecurityScheme().Initialize(record: null));
}
[Fact]
public void TermAttributeAttachedOnSecurityScheme()
{
// Arrange & Act
string qualifiedName = EdmVocabularyAnnotationExtensions.GetTermQualifiedName<SecurityScheme>();
// Assert
Assert.Equal("Org.OData.Authorization.V1.SecuritySchemes", qualifiedName);
}
[Fact]
public void InitializeSecuritySchemeWithRecordSuccess()
{
// Arrange
IEdmRecordExpression record = new EdmRecordExpression(
new EdmPropertyConstructor("Authorization", new EdmStringConstant("DelegatedWork")),
new EdmPropertyConstructor("RequiredScopes", new EdmCollectionExpression(
new EdmStringConstant("User.ReadAll"),
new EdmStringConstant("User.WriteAll"))));
SecurityScheme securityScheme = new SecurityScheme();
Assert.Null(securityScheme.Authorization);
Assert.Null(securityScheme.RequiredScopes);
// Act
securityScheme.Initialize(record);
// Assert
Assert.NotNull(securityScheme.Authorization);
Assert.Equal("DelegatedWork", securityScheme.Authorization);
Assert.NotNull(securityScheme.RequiredScopes);
Assert.Equal(2, securityScheme.RequiredScopes.Count);
Assert.Equal(new[] { "User.ReadAll", "User.WriteAll" }, securityScheme.RequiredScopes);
}
[Fact]
public void InitializeSecuritySchemeWorksWithCsdl()
{
// Arrange
string annotation = @"<Annotation Term=""Org.OData.Authorization.V1.SecuritySchemes"">
<Collection>
<Record>
<PropertyValue Property=""Authorization"" String=""DelegatedWork"" />
<PropertyValue Property=""RequiredScopes"" >
<Collection>
<String>User.ReadAll</String>
<String>User.WriteAll</String>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""Authorization"" String=""DelegatedPersonal"" />
<PropertyValue Property=""RequiredScopes"" >
<Collection>
<String>Directory.ReadAll</String>
<String>Directory.WriteAll</String>
</Collection>
</PropertyValue>
</Record>
</Collection>
</Annotation>";
IEdmModel model = GetEdmModel(annotation);
Assert.NotNull(model); // guard
Assert.NotNull(model.EntityContainer);
// Act
SecurityScheme[] schemes = model.GetCollection<SecurityScheme>(model.EntityContainer).ToArray();
// Assert
Assert.NotNull(schemes);
Assert.Equal(2, schemes.Length);
// #1
Assert.Equal("DelegatedWork", schemes[0].Authorization);
Assert.Equal(2, schemes[0].RequiredScopes.Count);
Assert.Equal(new[] { "User.ReadAll", "User.WriteAll" }, schemes[0].RequiredScopes);
// #2
Assert.Equal("DelegatedPersonal", schemes[1].Authorization);
Assert.Equal(2, schemes[1].RequiredScopes.Count);
Assert.Equal(new[] { "Directory.ReadAll", "Directory.WriteAll" }, schemes[1].RequiredScopes);
}
private IEdmModel GetEdmModel(string annotation)
{
const string template = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityContainer Name=""Container"">
{0}
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>";
string modelText = string.Format(template, annotation);
IEdmModel model;
bool result = CsdlReader.TryParse(XElement.Parse(modelText).CreateReader(), out model, out _);
Assert.True(result);
return model;
}
}
}

View file

@ -0,0 +1,104 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Xml.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
using Xunit;
namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests
{
public class ScopeTypeTests
{
[Fact]
public void DefaultPropertyAsNull()
{
// Arrange & Act
ScopeType scope = new ScopeType();
// Assert
Assert.Null(scope.Scope);
Assert.Null(scope.RestrictedProperties);
}
[Fact]
public void InitializeWithNullRecordThrows()
{
// Arrange & Act
ScopeType scope = new ScopeType();
// Assert
Assert.Throws<ArgumentNullException>("record", () => scope.Initialize(record: null));
}
[Fact]
public void InitializeWithScopeTypeRecordSuccess()
{
// Arrange
IEdmRecordExpression record = new EdmRecordExpression(
new EdmPropertyConstructor("Scope", new EdmStringConstant("name")),
new EdmPropertyConstructor("RestrictedProperties", new EdmStringConstant("abc,xyz")));
// Act
ScopeType scope = new ScopeType();
scope.Initialize(record);
// Assert
Assert.NotNull(scope.Scope);
Assert.Equal("name", scope.Scope);
Assert.NotNull(scope.RestrictedProperties);
Assert.Equal("abc,xyz", scope.RestrictedProperties);
}
[Fact]
public void ScopeTypeTermValueInitializeWorksForScopeType()
{
// Arrange
string annotation = @"<Annotation Term=""NS.MyTerm"">
<Record>
<PropertyValue Property=""Scope"" String=""name"" />
<PropertyValue Property=""RestrictedProperties"" String=""abc,xyz"" />
</Record>
</Annotation>";
IEdmModel model = GetEdmModel(annotation);
Assert.NotNull(model); // guard
// Act
ScopeType scope = model.GetRecord<ScopeType>(model.EntityContainer, "NS.MyTerm");
// Assert
Assert.NotNull(scope);
Assert.Equal("name", scope.Scope);
Assert.NotNull(scope.RestrictedProperties);
Assert.Equal("abc,xyz", scope.RestrictedProperties);
}
private IEdmModel GetEdmModel(string annotation)
{
const string template = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityContainer Name =""Default"">
{0}
</EntityContainer>
<Term Name=""MyTerm"" Type=""Capabilities.ScopeType"" />
</Schema>
</edmx:DataServices>
</edmx:Edmx>";
string modelText = string.Format(template, annotation);
IEdmModel model;
bool result = CsdlReader.TryParse(XElement.Parse(modelText).CreateReader(), out model, out _);
Assert.True(result);
return model;
}
}
}

View file

@ -4,6 +4,7 @@
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Microsoft.OData.Edm;
@ -29,7 +30,7 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Core.Tests
}
[Fact]
public void InitializeWithNullThrows()
public void InitializeWithNullRecordThrows()
{
// Arrange & Act
PrimitiveExampleValue value = new PrimitiveExampleValue();
@ -39,26 +40,56 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Core.Tests
}
[Fact]
public void InitializeWithNullThrows1()
public void InitializeWithPrimitiveValueRecordSuccess()
{
// Arrange & Act
// Arrange
IEdmRecordExpression record = new EdmRecordExpression(
new EdmPropertyConstructor("Description", new EdmStringConstant("HelloWorld!")),
new EdmPropertyConstructor("Value", new EdmBooleanConstant(true)));
PrimitiveExampleValue value = new PrimitiveExampleValue();
IEdmRecordExpression record = new EdmRecordExpression();
Assert.Null(value.Description);
Assert.Null(value.Value);
// Act
value.Initialize(record);
// Assert
// Assert.Throws<ArgumentNullException>("record", () => value.Initialize(record: null));
Assert.NotNull(value.Description);
Assert.Equal("HelloWorld!", value.Description);
Assert.NotNull(value.Value);
Assert.NotNull(value.Value.Value);
Assert.Equal(true, value.Value.Value);
}
public static IEnumerable<object[]> PrimitiveData =>
new List<object[]>
{
new object[] { @"String=""Hello World""", "Hello World" },
new object[] { @"Int=""42""", (long)42 },
new object[] { @"Bool=""true""", true },
new object[] { @"Bool=""false""", false },
new object[] { @"TimeOfDay=""15:38:25.1090000""", new TimeOfDay(15, 38, 25, 109) },
new object[] { @"Date=""2014-10-13""", new Date(2014, 10, 13) },
new object[] { @"Duration=""PT0S""", new TimeSpan() },
// new object[] { @"Binary=""AQ==""", new byte[] { 1 }, }, has problem in ODL?
new object[] { @"Float=""3.14""", 3.14 },
new object[] { @"Decimal=""3.14""", 3.14m },
new object[] { @"DateTimeOffset=""0001-01-01T00:00:00Z""", new DateTimeOffset() },
new object[] { @"Guid=""21EC2020-3AEA-1069-A2DD-08002B30309D""", new Guid("21EC2020-3AEA-1069-A2DD-08002B30309D") },
};
[Theory]
[InlineData(@"String""=""Hello World""")]
public void TargetOnEntityTypeReturnsCorrectTopSupportedValue1(string data)
[MemberData(nameof(PrimitiveData))]
public void PrimitiveExamplevalueInitializeWorksForPrimitiveData(string data, object except)
{
// Arrange
string annotation = $@"<Annotation Term=""Org.OData.Core.V1.Example"">
<Record Type=""Org.OData.Core.V1.PrimitiveExampleValue"">
<PropertyValue Property=""Description"" String=""Primitive example value"" />
<PropertyValue Property=""Value"" {data} />
</Record>";
</Record>
</Annotation>";
IEdmModel model = GetEdmModel(annotation);
Assert.NotNull(model); // guard
@ -75,6 +106,7 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Core.Tests
Assert.NotNull(value);
Assert.Equal("Primitive example value", value.Description);
Assert.NotNull(value.Value);
Assert.Equal(except, value.Value.Value);
}
private IEdmModel GetEdmModel(string annotation)
@ -91,12 +123,6 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Core.Tests
{0}
</Property>
</EntityType>
<EntityContainer Name =""Default"">
<Singleton Name=""Me"" Type=""NS.Customer"" />
</EntityContainer>
<Annotations Target=""NS.Customer/ID"">
{0}
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>";