Browse Source

Namespaces fixed and user token support

pull/1/head
Sebastian 10 years ago
parent
commit
b92daa0c06
  1. 2
      src/Squidex.Infrastructure/CQRS/Commands/IUserCommand.cs
  2. 2
      src/Squidex.Infrastructure/Json/LanguageConverter.cs
  3. 31
      src/Squidex.Infrastructure/Json/UserTokenConverter.cs
  4. 61
      src/Squidex.Infrastructure/UserToken.cs
  5. 2
      src/Squidex.Write/Apps/AppDomainObject.cs
  6. 2
      src/Squidex.Write/Apps/Commands/CreateApp.cs
  7. 1
      src/Squidex/Config/Domain/Serializers.cs
  8. 35
      src/Squidex/Pipeline/CommandHandlers/EnrichWithUserHandler.cs
  9. 1
      tests/Squidex.Infrastructure.Tests/LanguageTests.cs
  10. 131
      tests/Squidex.Infrastructure.Tests/UserTokenTests.cs
  11. 8
      tests/Squidex.Write.Tests/Apps/AppCommandHandlerTests.cs
  12. 14
      tests/Squidex.Write.Tests/Apps/AppDomainObjectTests.cs

2
src/Squidex.Infrastructure/CQRS/Commands/IUserCommand.cs

@ -10,6 +10,6 @@ namespace Squidex.Infrastructure.CQRS.Commands
{
public interface IUserCommand : ICommand
{
string UserId { get; set; }
UserToken User { get; set; }
}
}

2
src/Squidex.Infrastructure/Json/LanguageConverter.cs

@ -20,7 +20,7 @@ namespace Squidex.Infrastructure.Json
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return reader.TokenType == JsonToken.Null ? null : Language.GetLanguage((string) reader.Value);
return reader.TokenType == JsonToken.Null ? null : Language.GetLanguage((string)reader.Value);
}
public override bool CanConvert(Type objectType)

31
src/Squidex.Infrastructure/Json/UserTokenConverter.cs

@ -0,0 +1,31 @@
// ==========================================================================
// UserTokenConverter.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Newtonsoft.Json;
namespace Squidex.Infrastructure.Json
{
public sealed class UserTokenConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value.ToString());
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return reader.TokenType == JsonToken.Null ? null : UserToken.Parse((string)reader.Value);
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(UserToken);
}
}
}

61
src/Squidex.Infrastructure/UserToken.cs

@ -1,11 +1,64 @@
using System;
using System.Collections.Generic;
// ==========================================================================
// UserToken.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Squidex.Infrastructure
{
public sealed class UserToken
public sealed class UserToken : IEquatable<UserToken>
{
public string Type { get; }
public string Identifier { get; }
public UserToken(string type, string identifier)
{
Guard.NotNullOrEmpty(type, nameof(type));
Guard.NotNullOrEmpty(identifier, nameof(identifier));
Type = type.ToLowerInvariant();
Identifier = identifier;
}
public static UserToken Parse(string input)
{
Guard.NotNullOrEmpty(input, nameof(input));
var parts = input.Split(new [] { ':' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length < 2)
{
throw new ArgumentException("Input must have more than 2 parts divided by colon", nameof(input));
}
return new UserToken(parts[0], string.Join(":", parts.Skip(1)));
}
public override string ToString()
{
return $"{Type}:{Identifier}";
}
public override bool Equals(object obj)
{
return Equals(obj as UserToken);
}
public bool Equals(UserToken other)
{
return other != null && (ReferenceEquals(this, other) || (Type.Equals(other.Type) && Identifier.Equals(other.Identifier)));
}
public override int GetHashCode()
{
return (Type.GetHashCode() * 397) ^ (Identifier.GetHashCode());
}
}
}

2
src/Squidex.Write/Apps/AppDomainObject.cs

@ -175,7 +175,7 @@ namespace Squidex.Write.Apps
private static AppContributorAssigned CreateInitialOwner(IUserCommand command)
{
return new AppContributorAssigned { ContributorId = command.UserId, Permission = PermissionLevel.Owner };
return new AppContributorAssigned { ContributorId = command.User.Identifier, Permission = PermissionLevel.Owner };
}
private void ThrowIfNotCreated()

2
src/Squidex.Write/Apps/Commands/CreateApp.cs

@ -17,7 +17,7 @@ namespace Squidex.Write.Apps.Commands
{
public string Name { get; set; }
public string UserId { get; set; }
public UserToken User { get; set; }
public CreateApp()
{

1
src/Squidex/Config/Domain/Serializers.cs

@ -26,6 +26,7 @@ namespace Squidex.Config.Domain
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
settings.Converters.Add(new LanguageConverter());
settings.Converters.Add(new PropertiesBagConverter());
settings.Converters.Add(new UserTokenConverter());
settings.NullValueHandling = NullValueHandling.Ignore;
settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
settings.DateParseHandling = DateParseHandling.DateTime;

35
src/Squidex/Pipeline/CommandHandlers/EnrichWithUserHandler.cs

@ -9,6 +9,7 @@
using System.Security;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Infrastructure.Security;
// ReSharper disable InvertIf
@ -30,27 +31,33 @@ namespace Squidex.Pipeline.CommandHandlers
if (subjectCommand != null)
{
var subjectId = httpContextAccessor.HttpContext.User.OpenIdSubject();
var userToken =
FindUserFromSubject() ??
FindUserFromClient();
if (subjectId == null)
if (userToken == null)
{
var clientId = httpContextAccessor.HttpContext.User.OpenIdClientId();
if (clientId != null)
{
subjectId = $"Client:"
}
}
if (subjectId == null)
{
throw new SecurityException("No user with subject id available");
throw new SecurityException("No user with subject or client id available");
}
subjectCommand.UserId = subjectId;
subjectCommand.User = userToken;
}
return Task.FromResult(false);
}
private UserToken FindUserFromSubject()
{
var subjectId = httpContextAccessor.HttpContext.User.OpenIdSubject();
return subjectId == null ? null : new UserToken("subject", subjectId);
}
private UserToken FindUserFromClient()
{
var clientId = httpContextAccessor.HttpContext.User.OpenIdClientId();
return clientId == null ? null : new UserToken("client", clientId);
}
}
}

1
tests/Squidex.Infrastructure.Tests/LanguageTests.cs

@ -21,6 +21,7 @@ namespace Squidex.Infrastructure
static LanguageTests()
{
serializerSettings.Converters.Add(new LanguageConverter());
serializerSettings.NullValueHandling = NullValueHandling.Include;
}
[Theory]

131
tests/Squidex.Infrastructure.Tests/UserTokenTests.cs

@ -1,17 +1,138 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
// ==========================================================================
// UserTokenTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Newtonsoft.Json;
using Squidex.Infrastructure.Json;
using Xunit;
// ReSharper disable RedundantCast
namespace Squidex.Infrastructure
{
public class UserTokenTests
{
private static readonly JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
static UserTokenTests()
{
serializerSettings.Converters.Add(new UserTokenConverter());
serializerSettings.NullValueHandling = NullValueHandling.Include;
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(":")]
[InlineData("user")]
public void Should_throw_if_parsing_invalid_input(string input)
{
Assert.Throws<ArgumentException>(() => UserToken.Parse(input));
}
[Fact]
public void Should_instantiate_token()
{
var token = new UserToken("client", "client1");
Assert.Equal("client", token.Type);
Assert.Equal("client1", token.Identifier);
}
[Fact]
public void Should_instantiate_token_and_lower_type()
{
var token = new UserToken("Client", "client1");
Assert.Equal("client", token.Type);
Assert.Equal("client1", token.Identifier);
}
[Fact]
public void Should_parse_user_token_from_string()
{
var token = UserToken.Parse("")
var token = UserToken.Parse("client:client1");
Assert.Equal("client", token.Type);
Assert.Equal("client1", token.Identifier);
}
[Fact]
public void Should_parse_user_token_with_colon_in_identifier()
{
var token = UserToken.Parse("client:client1:app");
Assert.Equal("client", token.Type);
Assert.Equal("client1:app", token.Identifier);
}
[Fact]
public void Should_convert_user_token_to_string()
{
var token = UserToken.Parse("client:client1");
Assert.Equal("client:client1", token.ToString());
}
[Fact]
public void Should_make_correct_equal_comparisons()
{
var token1a = UserToken.Parse("client:client1");
var token1b = UserToken.Parse("client:client1");
var token2 = UserToken.Parse("client:client2");
Assert.True(token1a.Equals(token1b));
Assert.False(token1a.Equals(token2));
}
[Fact]
public void Should_make_correct_object_equal_comparisons()
{
var token1a = UserToken.Parse("client:client1");
object token1b = UserToken.Parse("client:client1");
object token2 = UserToken.Parse("client:client2");
Assert.True(token1a.Equals(token1b));
Assert.False(token1a.Equals(token2));
}
[Fact]
public void Should_provide_correct_hash_codes()
{
var token1a = UserToken.Parse("client:client1");
var token1b = UserToken.Parse("client:client1");
var token2 = UserToken.Parse("client:client2");
Assert.Equal(token1a.GetHashCode(), token1b.GetHashCode());
Assert.NotEqual(token1a.GetHashCode(), token2.GetHashCode());
}
[Fact]
public void Should_serialize_and_deserialize_null_token()
{
var input = Tuple.Create<UserToken>(null);
var json = JsonConvert.SerializeObject(input, serializerSettings);
var output = JsonConvert.DeserializeObject<Tuple<UserToken>>(json, serializerSettings);
Assert.Equal(output.Item1, input.Item1);
}
[Fact]
public void Should_serialize_and_deserialize_valid_token()
{
var input = Tuple.Create(UserToken.Parse("client:client1"));
var json = JsonConvert.SerializeObject(input, serializerSettings);
var output = JsonConvert.DeserializeObject<Tuple<UserToken>>(json, serializerSettings);
Assert.Equal(output.Item1, input.Item1);
}
}
}

8
tests/Squidex.Write.Tests/Apps/AppCommandHandlerTests.cs

@ -33,7 +33,7 @@ namespace Squidex.Write.Apps
private readonly Mock<IUserRepository> userRepository = new Mock<IUserRepository>();
private readonly AppCommandHandler sut;
private readonly AppDomainObject app;
private readonly string subjectId = Guid.NewGuid().ToString();
private readonly UserToken subjectId = new UserToken("subject", Guid.NewGuid().ToString());
private readonly string contributorId = Guid.NewGuid().ToString();
private readonly string clientSecret = Guid.NewGuid().ToString();
private readonly string clientName = "client";
@ -54,7 +54,7 @@ namespace Squidex.Write.Apps
[Fact]
public async Task Create_should_throw_if_a_name_with_same_name_already_exists()
{
var command = new CreateApp { Name = appName, AggregateId = Id, UserId = subjectId };
var command = new CreateApp { Name = appName, AggregateId = Id, User = subjectId };
var context = new CommandContext(command);
appRepository.Setup(x => x.FindAppByNameAsync(appName)).Returns(Task.FromResult(new Mock<IAppEntity>().Object)).Verifiable();
@ -70,7 +70,7 @@ namespace Squidex.Write.Apps
[Fact]
public async Task Create_should_create_app_if_name_is_free()
{
var command = new CreateApp { Name = appName, AggregateId = Id, UserId = subjectId };
var command = new CreateApp { Name = appName, AggregateId = Id, User = subjectId };
var context = new CommandContext(command);
appRepository.Setup(x => x.FindAppByNameAsync(appName)).Returns(Task.FromResult<IAppEntity>(null)).Verifiable();
@ -200,7 +200,7 @@ namespace Squidex.Write.Apps
private AppDomainObject CreateApp()
{
app.Create(new CreateApp { Name = appName, UserId = subjectId });
app.Create(new CreateApp { Name = appName, User = subjectId });
return app;
}

14
tests/Squidex.Write.Tests/Apps/AppDomainObjectTests.cs

@ -26,7 +26,7 @@ namespace Squidex.Write.Apps
{
private const string TestName = "app";
private readonly AppDomainObject sut;
private readonly string subjectId = Guid.NewGuid().ToString();
private readonly UserToken user = new UserToken("subject", Guid.NewGuid().ToString());
private readonly string contributorId = Guid.NewGuid().ToString();
private readonly string clientSecret = Guid.NewGuid().ToString();
private readonly string clientName = "client";
@ -54,17 +54,17 @@ namespace Squidex.Write.Apps
[Fact]
public void Create_should_specify_name_and_owner()
{
sut.Create(new CreateApp { Name = TestName, UserId = subjectId });
sut.Create(new CreateApp { Name = TestName, User = user });
Assert.Equal(TestName, sut.Name);
Assert.Equal(PermissionLevel.Owner, sut.Contributors[subjectId]);
Assert.Equal(PermissionLevel.Owner, sut.Contributors[user.Identifier]);
sut.GetUncomittedEvents().Select(x => x.Payload).ToArray()
.ShouldBeEquivalentTo(
new IEvent[]
{
new AppCreated { Name = TestName },
new AppContributorAssigned { ContributorId = subjectId, Permission = PermissionLevel.Owner },
new AppContributorAssigned { ContributorId = user.Identifier, Permission = PermissionLevel.Owner },
new AppLanguagesConfigured { Languages= new List<Language> { Language.GetLanguage("en") } }
});
}
@ -86,7 +86,7 @@ namespace Squidex.Write.Apps
{
CreateApp();
Assert.Throws<ValidationException>(() => sut.AssignContributor(new AssignContributor { ContributorId = subjectId, Permission = PermissionLevel.Editor }));
Assert.Throws<ValidationException>(() => sut.AssignContributor(new AssignContributor { ContributorId = user.Identifier, Permission = PermissionLevel.Editor }));
}
[Fact]
@ -123,7 +123,7 @@ namespace Squidex.Write.Apps
{
CreateApp();
Assert.Throws<ValidationException>(() => sut.RemoveContributor(new RemoveContributor { ContributorId = subjectId }));
Assert.Throws<ValidationException>(() => sut.RemoveContributor(new RemoveContributor { ContributorId = user.Identifier }));
}
[Fact]
@ -271,7 +271,7 @@ namespace Squidex.Write.Apps
private void CreateApp()
{
sut.Create(new CreateApp { Name = TestName, UserId = subjectId });
sut.Create(new CreateApp { Name = TestName, User = user });
((IAggregate)sut).ClearUncommittedEvents();
}

Loading…
Cancel
Save