Implement Config options

This commit is contained in:
Hao Kung 2014-05-05 15:39:34 -07:00
parent b623f725ba
commit ab84228c37
8 changed files with 122 additions and 149 deletions

View File

@ -20,11 +20,6 @@ namespace Microsoft.AspNet.Identity
UserName = ClaimTypes.Name; UserName = ClaimTypes.Name;
} }
public ClaimTypeOptions(IConfiguration config) : this()
{
IdentityOptions.Read(this, config);
}
/// <summary> /// <summary>
/// Claim type used for role claims /// Claim type used for role claims
/// </summary> /// </summary>

View File

@ -18,53 +18,6 @@ namespace Microsoft.AspNet.Identity
Lockout = new LockoutOptions(); Lockout = new LockoutOptions();
} }
public IdentityOptions(IConfiguration config)
{
ClaimType = new ClaimTypeOptions(config.GetSubKey("identity:claimtype"));
User = new UserOptions(config.GetSubKey("identity:user"));
Password = new PasswordOptions(config.GetSubKey("identity:password"));
//Lockout = new LockoutOptions(config.GetSubKey("identity:lockout"));
}
public static void Read(object obj, IConfiguration config)
{
var type = obj.GetType();
var props = type.GetTypeInfo().DeclaredProperties;
foreach (var prop in props)
{
// TODO: handle non string types?
if (!prop.CanWrite)
{
continue;
}
var configValue = config.Get(prop.Name);
if (configValue == null)
{
continue;
}
if (prop.PropertyType == typeof(string))
{
prop.SetValue(obj, configValue);
}
else if (prop.PropertyType == typeof(int))
{
// todo: TryParse/ errors?
prop.SetValue(obj, int.Parse(configValue));
}
else if (prop.PropertyType == typeof(bool))
{
// todo: TryParse/ errors?
prop.SetValue(obj, bool.Parse(configValue));
}
//else if (prop.PropertyType == typeof(TimeSpan))
//{
// // todo: TryParse/ errors?
// prop.SetValue(obj, TimeSpan.Parse(configValue));
//}
}
}
public ClaimTypeOptions ClaimType { get; set; } public ClaimTypeOptions ClaimType { get; set; }
public UserOptions User { get; set; } public UserOptions User { get; set; }

View File

@ -0,0 +1,64 @@
using System;
using System.Reflection;
using Microsoft.AspNet.ConfigurationModel;
using Microsoft.AspNet.DependencyInjection;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Configuration for lockout
/// </summary>
public class IdentityOptionsSetup : IOptionsSetup<IdentityOptions>
{
private readonly IConfiguration _config;
public IdentityOptionsSetup(IConfiguration config)
{
_config = config;
}
public int Order { get; set; }
public void Setup(IdentityOptions options)
{
ReadProperties(options.ClaimType, _config.GetSubKey("identity:claimtype"));
ReadProperties(options.User, _config.GetSubKey("identity:user"));
ReadProperties(options.Password, _config.GetSubKey("identity:password"));
ReadProperties(options.Lockout, _config.GetSubKey("identity:lockout"));
}
// TODO: Move this somewhere common (Config?)
public static void ReadProperties(object obj, IConfiguration config)
{
if (obj == null || config == null)
{
return;
}
var props = obj.GetType().GetTypeInfo().DeclaredProperties;
foreach (var prop in props)
{
if (!prop.CanWrite)
{
continue;
}
var configValue = config.Get(prop.Name);
if (configValue == null)
{
continue;
}
try
{
// No convert on portable
#if NET45 || K10
prop.SetValue(obj, Convert.ChangeType(configValue, prop.PropertyType));
#endif
}
catch
{
// TODO: what do we do about errors?
}
}
}
}
}

View File

@ -28,6 +28,7 @@ namespace Microsoft.AspNet.DependencyInjection
{ {
services.Add(IdentityServices.GetDefaultUserServices<TUser>()); services.Add(IdentityServices.GetDefaultUserServices<TUser>());
services.Add(IdentityServices.GetDefaultRoleServices<TRole>()); services.Add(IdentityServices.GetDefaultRoleServices<TRole>());
services.AddTransient<IOptionsSetup<IdentityOptions>, IdentityOptionsSetup>();
services.AddSingleton<IOptionsAccessor<IdentityOptions>, OptionsAccessor<IdentityOptions>>(); services.AddSingleton<IOptionsAccessor<IdentityOptions>, OptionsAccessor<IdentityOptions>>();
actionBuilder(new IdentityBuilder<TUser, TRole>(services)); actionBuilder(new IdentityBuilder<TUser, TRole>(services));
return services; return services;

View File

@ -1,44 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Configuration for lockout
/// </summary>
public class LockoutPolicy
{
/// <summary>
/// If true, will enable user lockout when users are created
/// </summary>
public bool UserLockoutEnabledByDefault { get; set; }
/// <summary>
/// Number of access attempts allowed for a user before lockout (if enabled)
/// </summary>
public int MaxFailedAccessAttemptsBeforeLockout { get; set; }
/// <summary>
/// Default amount of time an user is locked out for after MaxFailedAccessAttempsBeforeLockout is reached
/// </summary>
public TimeSpan DefaultAccountLockoutTimeSpan { get; set; }
}
}

View File

@ -13,11 +13,6 @@ namespace Microsoft.AspNet.Identity
RequiredLength = 6; RequiredLength = 6;
} }
public PasswordOptions(IConfiguration config) : this()
{
IdentityOptions.Read(this, config);
}
/// <summary> /// <summary>
/// Minimum required length /// Minimum required length
/// </summary> /// </summary>

View File

@ -10,11 +10,6 @@ namespace Microsoft.AspNet.Identity
//User.RequireUniqueEmail = true; // TODO: app decision? //User.RequireUniqueEmail = true; // TODO: app decision?
} }
public UserOptions(IConfiguration config) : this()
{
IdentityOptions.Read(this, config);
}
/// <summary> /// <summary>
/// Only allow [A-Za-z0-9@_] in UserNames /// Only allow [A-Za-z0-9@_] in UserNames
/// </summary> /// </summary>

View File

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNet.ConfigurationModel; using Microsoft.AspNet.ConfigurationModel;
using Microsoft.AspNet.ConfigurationModel.Sources; using Microsoft.AspNet.ConfigurationModel.Sources;
using Microsoft.AspNet.DependencyInjection;
using Microsoft.AspNet.DependencyInjection.Fallback;
using Xunit; using Xunit;
namespace Microsoft.AspNet.Identity.Test namespace Microsoft.AspNet.Identity.Test
@ -58,11 +60,21 @@ namespace Microsoft.AspNet.Identity.Test
{"identity:password:RequireNonLetterOrDigit", "false"}, {"identity:password:RequireNonLetterOrDigit", "false"},
{"identity:password:RequireUpperCase", "false"}, {"identity:password:RequireUpperCase", "false"},
{"identity:password:RequireDigit", "false"}, {"identity:password:RequireDigit", "false"},
{"identity:password:RequireLowerCase", "false"} {"identity:password:RequireLowerCase", "false"},
{"identity:lockout:EnabledByDefault", "TRUe"},
{"identity:lockout:MaxFailedAccessAttempts", "1000"}
}; };
var config = new ConfigurationModel.Configuration { new MemoryConfigurationSource(dic) }; var config = new ConfigurationModel.Configuration { new MemoryConfigurationSource(dic) };
Assert.Equal(roleClaimType, config.Get("identity:claimtype:role")); Assert.Equal(roleClaimType, config.Get("identity:claimtype:role"));
var options = new IdentityOptions(config);
var setup = new IdentityOptionsSetup(config);
var services = new ServiceCollection();
services.AddInstance<IConfiguration>(config);
services.AddTransient<IOptionsSetup<IdentityOptions>, IdentityOptionsSetup>();
services.AddTransient<IOptionsAccessor<IdentityOptions>, OptionsAccessor<IdentityOptions>>();
var accessor = services.BuildServiceProvider().GetService<IOptionsAccessor<IdentityOptions>>();
Assert.NotNull(accessor);
var options = accessor.Options;
Assert.Equal(roleClaimType, options.ClaimType.Role); Assert.Equal(roleClaimType, options.ClaimType.Role);
Assert.Equal(useridClaimType, options.ClaimType.UserId); Assert.Equal(useridClaimType, options.ClaimType.UserId);
Assert.Equal(usernameClaimType, options.ClaimType.UserName); Assert.Equal(usernameClaimType, options.ClaimType.UserName);
@ -75,51 +87,53 @@ namespace Microsoft.AspNet.Identity.Test
Assert.False(options.Password.RequireNonLetterOrDigit); Assert.False(options.Password.RequireNonLetterOrDigit);
Assert.False(options.Password.RequireUppercase); Assert.False(options.Password.RequireUppercase);
Assert.Equal(10, options.Password.RequiredLength); Assert.Equal(10, options.Password.RequiredLength);
Assert.True(options.Lockout.EnabledByDefault);
Assert.Equal(1000, options.Lockout.MaxFailedAccessAttempts);
} }
[Fact] //[Fact]
public void ClaimTypeOptionsFromConfig() //public void ClaimTypeOptionsFromConfig()
{ //{
const string roleClaimType = "rolez"; // const string roleClaimType = "rolez";
const string usernameClaimType = "namez"; // const string usernameClaimType = "namez";
const string useridClaimType = "idz"; // const string useridClaimType = "idz";
const string securityStampClaimType = "stampz"; // const string securityStampClaimType = "stampz";
var dic = new Dictionary<string, string> // var dic = new Dictionary<string, string>
{ // {
{"role", roleClaimType}, // {"role", roleClaimType},
{"username", usernameClaimType}, // {"username", usernameClaimType},
{"userid", useridClaimType}, // {"userid", useridClaimType},
{"securitystamp", securityStampClaimType} // {"securitystamp", securityStampClaimType}
}; // };
var config = new ConfigurationModel.Configuration {new MemoryConfigurationSource(dic)}; // var config = new ConfigurationModel.Configuration {new MemoryConfigurationSource(dic)};
Assert.Equal(roleClaimType, config.Get("role")); // Assert.Equal(roleClaimType, config.Get("role"));
var options = new ClaimTypeOptions(config); // var options = new ClaimTypeOptions(config);
Assert.Equal(roleClaimType, options.Role); // Assert.Equal(roleClaimType, options.Role);
Assert.Equal(useridClaimType, options.UserId); // Assert.Equal(useridClaimType, options.UserId);
Assert.Equal(usernameClaimType, options.UserName); // Assert.Equal(usernameClaimType, options.UserName);
Assert.Equal(securityStampClaimType, options.SecurityStamp); // Assert.Equal(securityStampClaimType, options.SecurityStamp);
} //}
[Fact] //[Fact]
public void PasswordOptionsFromConfig() //public void PasswordOptionsFromConfig()
{ //{
var dic = new Dictionary<string, string> // var dic = new Dictionary<string, string>
{ // {
{"RequiredLength", "10"}, // {"RequiredLength", "10"},
{"RequireNonLetterOrDigit", "false"}, // {"RequireNonLetterOrDigit", "false"},
{"RequireUpperCase", "false"}, // {"RequireUpperCase", "false"},
{"RequireDigit", "false"}, // {"RequireDigit", "false"},
{"RequireLowerCase", "false"} // {"RequireLowerCase", "false"}
}; // };
var config = new ConfigurationModel.Configuration { new MemoryConfigurationSource(dic) }; // var config = new ConfigurationModel.Configuration { new MemoryConfigurationSource(dic) };
var options = new PasswordOptions(config); // var options = new PasswordOptions(config);
Assert.False(options.RequireDigit); // Assert.False(options.RequireDigit);
Assert.False(options.RequireLowercase); // Assert.False(options.RequireLowercase);
Assert.False(options.RequireNonLetterOrDigit); // Assert.False(options.RequireNonLetterOrDigit);
Assert.False(options.RequireUppercase); // Assert.False(options.RequireUppercase);
Assert.Equal(10, options.RequiredLength); // Assert.Equal(10, options.RequiredLength);
} //}
} }
} }