extended OrmLiteAuthRepository not binding properly - servicestack

I extended the class OrmLiteAuthRepository
In the app host i inject it into the container. I test it using requiredrole controller and it never calls the methods for my custom security checks.
Even though i get redirect to http://localhost:5000/?redirect=%2fRequiresRole#f=Unauthorized
SO i just verified the the main simple contrustor is called when teh application starts. So it is using my clss. but not calling the get\haspermission methods.
[RequiredRole("TheRole")]
public class RequiresRoleController : ServiceStackController
{
public ActionResult Index()
{
var session = SessionAs<CustomUserSession>();
return View(session);
}
}
using System;
using System.Collections.Generic;
using cbw.service.interfaces.Services;
using ServiceStack;
using ServiceStack.Auth;
using ServiceStack.Data;
using ServiceStack.Host;
using ServiceStack.Messaging;
namespace cbw.mvc.web.service.Providers
{
public class MyOrmLiteAuthRepository : OrmLiteAuthRepository
{
public MyOrmLiteAuthRepository(IDbConnectionFactory dbFactory) : base(dbFactory) { }
public MyOrmLiteAuthRepository(IDbConnectionFactory dbFactory, string namedConnnection = null)
: base(dbFactory, namedConnnection)
{
DbFactory = dbFactory;
NamedConnnection = namedConnnection;
}
public IDbConnectionFactory DbFactory { get; set; }
public string NamedConnnection { get; set; }
public override ICollection<string> GetPermissions(string userAuthId)
{
var permissions = base.GetPermissions(userAuthId);
using (var ss = HostContext.ResolveService<SecurityService>(new BasicRequest()))
{
permissions = ss.UserPermissions(Convert.ToInt32(userAuthId));
}
return permissions;
}
public override bool HasPermission(string userAuthId, string permission)
{
var hasPermission = base.HasPermission(userAuthId, permission);
using (var ss = HostContext.ResolveService<SecurityService>(new BasicRequest()))
{
hasPermission = ss.UserHasPermInRoleOrGroup(permission, Convert.ToInt32(userAuthId));
}
return hasPermission;
}
}
}
Apphost.cs
using System;
using System.Net;
using cbw.mvc.web.service.Providers;
using cbw.service.interfaces.Services;
using cbw.service.interfaces.Validators;
using cbw.service.models.Models;
using ServiceStack;
using ServiceStack.Auth;
using ServiceStack.OrmLite;
using ServiceStack.Caching;
using ServiceStack.Data;
using ServiceStack.Mvc;
using ServiceStack.Text;
using ServiceStack.Validation;
namespace cbw.mvc.web.service
{
public class AppHost : AppHostBase
{
public AppHost() : base("ServiceStack + .NET Core", typeof(StartupService).Assembly) { }
public override void Configure(Funq.Container container)
{
Plugins.Add(new RazorFormat());
//Works but recommend handling 404 at end of .NET Core pipeline
//this.CustomErrorHttpHandlers[HttpStatusCode.NotFound] = new RazorHandler("/notfound");
this.CustomErrorHttpHandlers[HttpStatusCode.Unauthorized] = new RazorHandler("/login");
//To include null values in the json globally
JsConfig.IncludeNullValues = true;
//This is mandate. We need "IncludeNullValuesInDictionaries = true" to include null values
JsConfig.IncludeNullValuesInDictionaries = true;
//To automatically wired up for you on all HTTP Verbs (GET, POST, etc)
//And built-in endpoints, i.e. JSON, XML, JSV, HTML, CSV, SOAP
Plugins.Add(new CorsFeature());
//To add registration feature
Plugins.Add(new RegistrationFeature());
//To add validation feature
Plugins.Add(new ValidationFeature());
container.RegisterValidators(
typeof(InsertCompanyValidator).Assembly,
typeof(UpdateCompanyValidator).Assembly,
typeof(DeleteCompanyValidator).Assembly
);
Plugins.Add(new AuthFeature(() => new CustomUserSession(),
new IAuthProvider[]
{
new CredentialsAuthProvider(), //HTML Form post of UserName/Password credentials
new BasicAuthProvider(), //Sign-in with HTTP Basic Auth
new DigestAuthProvider(AppSettings), //Sign-in with HTTP Digest Auth
new TwitterAuthProvider(AppSettings), //Sign-in with Twitter
new FacebookAuthProvider(AppSettings), //Sign-in with Facebook
new GithubAuthProvider(AppSettings), //Sign-in with GitHub OAuth Provider
new GoogleAuthProvider(AppSettings), //Sign-in with Google OAuth Provider
new YandexAuthProvider(AppSettings), //Sign-in with Yandex OAuth Provider
new VkAuthProvider(AppSettings), //Sign-in with VK.com OAuth Provider
})
{
HtmlRedirect = "/",
//IncludeRegistrationService = true,
});
// i.e. Register in Memory Cache Client
//AutoQuery
Plugins.Add(new AutoQueryFeature { MaxLimit = 100000 });
container.Register<IAuthRepository>(c =>
new MyOrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>())
{
UseDistinctRoleTables = AppSettings.Get("UseDistinctRoleTables", true),
});
;
bool ShouldWipeAndReloadDb = false;
var environmentVariable = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (environmentVariable == "LocalMemory" || environmentVariable == "LocalSQLServer")
{
ShouldWipeAndReloadDb = true;
//Init auth tables
container.Resolve<IAuthRepository>().InitSchema();
}
var authRepo = (MyOrmLiteAuthRepository)container.Resolve<IAuthRepository>();
//Wipe and reload if using in memory SQL
if (ShouldWipeAndReloadDb)
{
DatabaseInitService dis = new DatabaseInitService();
dis.ResetDatabase();
SessionService.ResetUsers(authRepo);
dis.InitializeTablesAndData();
}
}
}
}

You’re using [RequiredRole] but you’re only overriding the HasPermission/GetPermissions APIs, you need to have overridden the HasRole/GetRoles APIs instead.

Related

System.IO.InvalidDataException : ServiceStackHost.Instance has already been set (BasicAppHost)

I'm getting an error when i try to run some tests on my servicestack web service.
I'm using ServiceStack 4.5.8 and Nunit 3.5. The solution was created initially from a ServiceStackVS template.
The error, which appears on a number of tests, is
System.IO.InvalidDataException : ServiceStackHost.Instance has already been set (BasicAppHost)</br>
TearDown : System.NullReferenceException : Object reference not set to an instance of an object.</br>
at ServiceStack.ServiceStackHost.Init()</br>
at MyApp.Tests.EchoServiceUnitTests.OneTimeSetup() in </br>
C:\Repos\MyApp\Myapp\MyApp.Tests\EchoServiceUnitTests.cs:line 45 </br>
--TearDown</br>
at MyApp.Tests.EchoServiceUnitTests.TestFixtureTearDown() in </br>C:\Repos\MyApp\MyApp\MyApp.Tests\EchoServiceUnitTests.cs:line 54
One of the tests that regularly generates this error is
namespace Tests
{
[TestFixture]
public class EchoServiceUnitTests
{
private ServiceStackHost appHost;
[OneTimeSetUp]
public void OneTimeSetup()
{
this.appHost = new BasicAppHost(typeof(EchoService).Assembly).Init();
}
[OneTimeTearDown]
public void TestFixtureTearDown()
{
this.appHost.Dispose();
}
[Test]
public void TestService()
{
const string Message = "Hello";
var service = this.appHost.Container.Resolve <EchoService>();
var response = (EchoResponse)service.Any(new Echo
{
Message = Message
});
Assert.That(response.Message,
Is.EqualTo(Message));
}
}
}
the service for this is
namespace ServiceInterface
{
public class EchoService : Service
{
public object Any(Echo request)
{
return new EchoResponse {Message = request.Message};
}
}
}
[Route("/Echo")]
[Route("/Echo/{Message}")]
public class Echo : IReturn<EchoResponse>
{
public string Message { get; set; }
}
public class EchoResponse : IHasResponseStatus
{
public EchoResponse()
{
this.ResponseStatus = new ResponseStatus();
}
public string Message { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
And finally my apphost
namespace MyApplication
{
using System;
using Funq;
using ServiceInterface;
using ServiceModel.Validators;
using ServiceStack;
using ServiceStack.Admin;
using ServiceStack.Api.Swagger;
using ServiceStack.Caching;
using ServiceStack.Configuration;
using ServiceStack.Logging;
using ServiceStack.Logging.NLogger;
using ServiceStack.MsgPack;
using ServiceStack.OrmLite;
using ServiceStack.OrmLite.SqlServer.Converters;
using ServiceStack.ProtoBuf;
using ServiceStack.Razor;
using ServiceStack.Validation;
using ServiceStack.VirtualPath;
using ServiceStack.Wire;
public class AppHost : AppHostBase
{
public static ILog Log = LogManager.GetLogger(typeof(AppHost));
public AppHost()
: base("MyApp",
typeof(HelloService).Assembly) { }
public override void Configure(Container container)
{
LogManager.LogFactory = new NLogFactory();
Log = LogManager.GetLogger(this.GetType());
this.Plugins.Add(new RazorFormat());
this.Plugins.Add(new PostmanFeature());
this.Plugins.Add(new SwaggerFeature());
this.Plugins.Add(new AdminFeature());
var ormSettings = new AppSettings();
container.Register <ICacheClient>(new MemoryCacheClient());
var dbFactory = new OrmLiteConnectionFactory(ormSettings.GetString("SqlDbConnection"),
SqlServerDialect.Provider);
dbFactory.RegisterConnection("Database2",
ormSettings.GetString("Sql2Connection"),
SqlServerDialect.Provider);
SqlServerDialect.Provider.RegisterConverter<DateTime?>(new SqlServerDateTimeConverter());
this.Plugins.Add(new RequestLogsFeature
{
RequestLogger = new CsvRequestLogger(files: new FileSystemVirtualPathProvider(this,
this.Config.WebHostPhysicalPath),
requestLogsPattern: "requestlogs/{year}-{month}/{year}-{month}-{day}.csv",
errorLogsPattern: "requestlogs/{year}-{month}/{year}-{month}-{day}-errors.csv",
appendEvery: TimeSpan.FromSeconds(1)),
EnableRequestBodyTracking = true,
EnableResponseTracking = true,
EnableErrorTracking = true,
});
this.Plugins.Add(new AutoQueryDataFeature
{
MaxLimit = 1000
});
this.Plugins.Add(new AutoQueryFeature());
var sse = new ServerEventsFeature
{
StreamPath = "/event-stream",
HeartbeatPath = "/event-heartbeat",
UnRegisterPath = "/event-unregister",
SubscribersPath = "/event-subscribers",
LimitToAuthenticatedUsers = false,
IdleTimeout = TimeSpan.FromSeconds(30),
HeartbeatInterval = TimeSpan.FromSeconds(10),
NotifyChannelOfSubscriptions = true,
};
this.Plugins.Add(sse);
Plugins.Add(new AdminFeature());
Plugins.Add(new WireFormat());
Plugins.Add(new MsgPackFormat());
Plugins.Add(new ProtoBufFormat());
}
}
}
I've tried a variety of suggestions including making the apphost in the test static, but nothing seems to work for me. I then tried the following test which also generated the same error which suggests to me that there is something in the apphost which is wrong but I can't see what.
[TestFixture(Category = "AppHost")]
public class AppHostTests
{
/// <summary>
/// The app host doesnt throw exception.
/// </summary>
[Test]
public void AppHostDoesntThrowException()
{
var apphost = new AppHost();
Assert.That(() => apphost.Init(),
Throws.Nothing);
}
}
The tests that generate this error whether I am using NCRUNCH (set to run one at a time) or if I use resharpers run all tests. It's generally the same tests that generate this error, though that seems to vary. In all cases, if I then run the tests manually they all pass.
You can only have 1 AppHost initialized and running at the same time where somehow NCrunch test is being run whilst there is another AppHost still in use. Maybe you can try debugging and setting a breakpoint that checks if ServiceStackHost.Instance is not null before trying to initialize another AppHost.
Note the AppHostBase is an ASP.NET Web App which may be causing the interference if it's running in the same project as the unit tests. If you want an integration test use AppSelfHostBase instead which you would use in place of BasicAppHost where you'd want to run a full integration test.

ASP.NET Core MVC 6 Azure B2C Active Directory Authentication issue

I followed the article : https://github.com/Azure-Samples/active-directory-dotnet-webapp-openidconnect-aspnetcore-b2c
In this sample app there is a Sign-in button. I am able to Sign-in successfully by clicking Sign-In button by providing my Azure B2C Tenant and registering the application in the tenant.
In another app, I want to authenticate without the Sign-In button being clicked i.e. right when I open the URL, I get redirected first to the Azure B2C AD login page, and after successful validation of credentials, I should be able to see the home screen.
So, what I did was from the URL mentioned from the article, I copied the SiginIn() method as:
public async Task<IActionResult> Index()
{
await SignIn();
await GetDataAsync();
}
I get an error message on running the application as : InvalidOperationException: No authentication handler is configured to handle the scheme: b2c_1_org_b2c_global_signin
Please advise how can I authenticate directly without the signin button. Previously with MVC5, I have successfully done this where I used [Authorize] attribute on the Controller class.
Controller Code with Index method
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using System.IO;
using System.Net;
using System.Text;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Hosting;
using WebViewerCore.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Authorization;
namespace WebViewerCore.Controllers
{
[Authorize]
public class DocumentController : Controller
{
#region GlobalVariables
private static readonly string serviceUrl = "";
private string doctype = string.Empty;
private string dmsno = string.Empty;
public string documentName = string.Empty;
private string errMsg = string.Empty;
StringBuilder msg;
Document doc;
private IHostingEnvironment _env;
private IConfiguration _config;
#endregion
#region C'tor
public DocumentController(IHostingEnvironment env, IConfiguration config)
{
_env = env;
_config = config;
}
#endregion
#region ControllerAction
public async Task<IActionResult> Index()
{
//return View();
try
{
//await SignIn();
string storageAccount = _config.GetSection("BlobStorage").GetSection("StorageAccount").Value;
string storageContainer = _config.GetSection("BlobStorage").GetSection("StorageContainer").Value;
ViewBag.StorageAccount = storageAccount;
ViewBag.StorageContainer = storageContainer;
await GetDataAsync();
//HttpContext.Response.ContentType = "application/vnd.ms-xpsdocument";
if (TempData["QueryStringMissing"] != null && (bool)TempData["QueryStringMissing"] || doc == null)
{
return View("View");
}
else
{
return View("Index", doc);
}
}
catch (Exception ex)
{
//logger.LogErrorWithMessage(ex, ex.StackTrace);
//return View("Error", new HandleErrorInfo(ex, "Document", "Index"));
throw ex;
}
}
#endregion
Startup.cs code
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
using Microsoft.AspNetCore.Http;
using System.IO;
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authentication.Cookies;
namespace WebViewerCore
{
public class Startup
{
#region Global Variables
public static string SignUpPolicyId;
public static string SignInPolicyId;
public static string ProfilePolicyId;
public static string ClientId;
public static string RedirectUri;
public static string AadInstance;
public static string Tenant;
#endregion
public Startup(IHostingEnvironment env)
{
//var builder = new ConfigurationBuilder()
// .SetBasePath(env.ContentRootPath)
// .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
// .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
// .AddEnvironmentVariables();
//Configuration = builder.Build();
Configuration = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables()
.Build();
}
public IConfigurationRoot Configuration { get; set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
// Adds a default in-memory implementation of IDistributedCache.
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.CookieHttpOnly = true;
});
services.AddSingleton<IConfiguration>(Configuration);
// Add Authentication services.
services.AddAuthentication(sharedOptions => sharedOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Document}/{action=Index}/{id?}");
});
// App config settings
ClientId = Configuration["AzureAD:ClientId"];
AadInstance = Configuration["AzureAD:AadInstance"];
Tenant = Configuration["AzureAD:Tenant"];
RedirectUri = Configuration["AzureAD:RedirectUri"];
// B2C policy identifiers
SignUpPolicyId = Configuration["AzureAD:SignUpPolicyId"];
SignInPolicyId = Configuration["AzureAD:SignInPolicyId"];
// Configure the OWIN pipeline to use OpenID Connect auth.
//app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(SignUpPolicyId));
app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(SignInPolicyId));
}
private OpenIdConnectOptions CreateOptionsFromPolicy(string policy)
{
policy = policy.ToLower();
return new OpenIdConnectOptions
{
// For each policy, give OWIN the policy-specific metadata address, and
// set the authentication type to the id of the policy
MetadataAddress = string.Format(AadInstance, Tenant, policy),
AuthenticationScheme = policy,
CallbackPath = new PathString(string.Format("/{0}", policy)),
// These are standard OpenID Connect parameters, with values pulled from config.json
ClientId = ClientId,
PostLogoutRedirectUri = RedirectUri,
Events = new OpenIdConnectEvents
{
OnRemoteFailure = RemoteFailure,
},
ResponseType = OpenIdConnectResponseType.IdToken,
// This piece is optional - it is used for displaying the user's name in the navigation bar.
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
}
};
}
// Used for avoiding yellow-screen-of-death
private Task RemoteFailure(FailureContext context)
{
context.HandleResponse();
if (context.Failure is OpenIdConnectProtocolException && context.Failure.Message.Contains("access_denied"))
{
context.Response.Redirect("/");
}
else
{
context.Response.Redirect("/Home/Error?message=" + context.Failure.Message);
}
return Task.FromResult(0);
}
}
}
To automatically redirect users navigating to a specific controller or endpoint in MVC, all you need to do is add the [Authorize] attribute, provided you've configured your middleware correctly.
In the case of Azure AD B2C, you need to make sure you add the OpenID Middleware like so:
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
// For each policy, give OWIN the policy-specific metadata address, and
// set the authentication type to the id of the policy
MetadataAddress = string.Format(AadInstance, Tenant, policy),
AuthenticationScheme = policy,
CallbackPath = new PathString(string.Format("/{0}", policy)),
// These are standard OpenID Connect parameters, with values pulled from config.json
ClientId = ClientId,
PostLogoutRedirectUri = RedirectUri,
Events = new OpenIdConnectEvents
{
OnRemoteFailure = RemoteFailure,
},
ResponseType = OpenIdConnectResponseType.IdToken,
// This piece is optional - it is used for displaying the user's name in the navigation bar.
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
},
};);
The sample you referenced already does what you want, to a point.
In that sample, if you haven't signed in and navigate to /about, you'll get automatically redirected to Azure AD B2C to sign in.
As it stands, the sample has the [Authorize] attribute only on a controller action in the Home controller, you'll want to move that up to the controller level and add it to every controller. Then you can just remove the the sign-in/sign-up/sign-out buttons and controller action.

CKfinder- Dynamic User folder -Asp.net MVC 5

I am using Asp.NET MVC 5 to build a web application. I downloaded Ckeditor and CKfinder Connector for ASP.NET. I was able to follow the instructions and get Ckeditor and Ckfinder integration to work.
I am trying to figure out how I can have dynamic folder directory in CkFinder per logged in user. According to the instructions provided in http://docs.cksource.com/ckfinder3-net/howto.html#howto_private_folders it tells you to do that in connectorBuilder .SetRequestConfiguration. The problem is that ConnectorBuilder is being setup on the startup and the user logs in after that?
Here is the code that i have now where everything works except the icons
using DearColleagueV2.Models;
[assembly: Microsoft.Owin.OwinStartup(typeof(DearColleagueV2.Startup))]
namespace DearColleagueV2
{
using System.Configuration;
using CKSource.CKFinder.Connector.Config;
using CKSource.CKFinder.Connector.Core.Builders;
using CKSource.CKFinder.Connector.Core.Logs;
using CKSource.CKFinder.Connector.Host.Owin;
using CKSource.CKFinder.Connector.Logs.NLog;
using CKSource.CKFinder.Connector.KeyValue.EntityFramework;
using CKSource.FileSystem.Dropbox;
using CKSource.FileSystem.Local;
using System;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;
using Microsoft.Owin.Security;
using CKSource.CKFinder.Connector.Core.Acl;
using System.Collections.Generic;
using CKSource.CKFinder.Connector.Core.Authentication;
using System.Threading.Tasks;
using CKSource.CKFinder.Connector.Core;
using System.Threading;
using System.Security.Cryptography;
using System.Text;
public partial class Startup
{
public void Configuration(IAppBuilder builder)
{
LoggerManager.LoggerAdapterFactory = new NLogLoggerAdapterFactory();
ConfigureAuthForIdentity(builder);
RegisterFileSystems();
var connectorBuilder = ConfigureConnector();
var connector = connectorBuilder.Build(new OwinConnectorFactory());
builder.Map("/CKFinder/connector", builder1 => builder1.UseConnector(connector));
}
private void ConfigureAuthForIdentity(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
public ConnectorBuilder ConfigureConnector()
{
var connectorBuilder = new ConnectorBuilder();
connectorBuilder
.SetRequestConfiguration(
(request, config) =>
{
//config.AddProxyBackend("local", new LocalStorage(#"MyFiles"));
var userName = request.Principal?.Identity?.Name;
if (userName != null)
{
var sha = new SHA1CryptoServiceProvider();
var hash = sha.ComputeHash(Encoding.UTF8.GetBytes(userName));
var folderName = BitConverter.ToString(hash).Replace("-", string.Empty);
config.AddProxyBackend("local", new LocalStorage(#"c:\files"));
config.AddResourceType("private", resourceBuilder => resourceBuilder.SetBackend("local", folderName));
config.SetThumbnailBackend("local", "thumbs");
config.AddAclRule(new AclRule(
new StringMatcher("*"), new StringMatcher("/"), new StringMatcher("*"),
new Dictionary<Permission, PermissionType>
{
{ Permission.FolderView, PermissionType.Allow },
{ Permission.FolderCreate, PermissionType.Allow },
{ Permission.FolderRename, PermissionType.Allow },
{ Permission.FolderDelete, PermissionType.Allow },
{ Permission.FileView, PermissionType.Allow },
{ Permission.FileCreate, PermissionType.Allow },
{ Permission.FileRename, PermissionType.Allow },
{ Permission.FileDelete, PermissionType.Allow },
{ Permission.ImageResize, PermissionType.Allow },
{ Permission.ImageResizeCustom, PermissionType.Allow }
}));
}
})
.SetAuthenticator(new MyAuthenticator());
return connectorBuilder;
}
private static void RegisterFileSystems()
{
FileSystemFactory.RegisterFileSystem<LocalStorage>();
FileSystemFactory.RegisterFileSystem<DropboxStorage>();
}
}
public class MyAuthenticator : IAuthenticator
{
public Task<CKSource.CKFinder.Connector.Core.Authentication.IUser> AuthenticateAsync(ICommandRequest commandRequest, CancellationToken cancellationToken)
{
var user = new User(true, null);
return Task.FromResult((CKSource.CKFinder.Connector.Core.Authentication.IUser)user);
}
}
}
The SetRequestConfiguration method of the ConnectorBuilder class accepts an action that will be called for each request.
The code from the example you linked, although defined during startup, will be executed for every request.
Additionally you should make sure that the user is already logged in when she is trying to use CKFinder. For example:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var connectorFactory = new OwinConnectorFactory();
var connectorBuilder = ...
var connector = connectorBuilder.Build(connectorFactory);
app.UseCookieAuthentication(
/*
* Your CookieAuthenticationOptions that will redirect anonymous
* users to the login page
*/
);
app.UseConnector(connector);
}
}
About missing thumbnails, you should add at least one allowed thumbnail size. Just add something like config.SetThumbnailSizes(new SizeAndQuality(100, 100, new ImageQuality(80))); to the action executed in SetRequestConfiguration.

UserId not found error in aspnet Identity at GenerateUserIdentityAsync method

I am getting UserId not found error after registring a user and also after login.Moreoever, after registration, data is saved to database and in dbo.AspNetUsers table, id column is auto incremented and return type is int.
There is UserId Column in AspNetUserClaims table.It has 4 Col---Id,UserId,ClaimType,ClaimValue.It has Id column as auto incremented not the userId.
I was initially successfully changed Primary key from string to int by following this link---http://www.asp.net/identity/overview/extensibility/change-primary-key-for-users-in-aspnet-identity.
It was running succesfully before but now it is giving me error at this line---
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
Exception Details: System.InvalidOperationException: UserId not found.
This is the complete stack trace. you can see it here----http://pastebin.com/0hp5eAnp
It was working fine earlier but now when i added foreign key relationship with other tables, i don't know what is missing there. In the database all the tables are created properly with proper relationship between them but something is missing here.
My ApplicationUser class is something like this-------
public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public ApplicationUser()
{
this.Posts = new HashSet<Post>();
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public class CustomUserRole : IdentityUserRole<int> { }
public class CustomUserClaim : IdentityUserClaim<int> { }
public class CustomUserLogin : IdentityUserLogin<int> { }
public class CustomRole : IdentityRole<int, CustomUserRole>
{
public CustomRole() { }
public CustomRole(string name) { Name = name; }
}
public class CustomUserStore : UserStore<ApplicationUser, CustomRole, int,
CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public CustomUserStore(ApplicationDbContext context)
: base(context)
{
}
}
public class CustomRoleStore : RoleStore<CustomRole, int, CustomUserRole>
{
public CustomRoleStore(ApplicationDbContext context)
: base(context)
{
}
}
and my IdentityConfig.cs class file is something like this-------
// Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application.
public class ApplicationUserManager : UserManager<ApplicationUser, int>
{
public ApplicationUserManager(IUserStore<ApplicationUser, int> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new CustomUserStore(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser, int>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 1,
//RequireNonLetterOrDigit = true,
//RequireDigit = true,
//RequireLowercase = true,
//RequireUppercase = true,
};
// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
// You can write your own provider and plug it in here.
manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser, int>
{
MessageFormat = "Your security code is {0}"
});
manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser, int>
{
Subject = "Security Code",
BodyFormat = "Your security code is {0}"
});
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser, int>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
}
// Configure the application sign-in manager which is used in this application.
public class ApplicationSignInManager : SignInManager<ApplicationUser, int>
{
public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
}
public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
{
return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
}
public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
{
return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
}
}
i have seen many stackoverflow answers but not getting it to work.Can someone plzz plzz see what is missing, what should i do now.thanks in advance.
Here, in the applicationUser class, at the Id column, it showing some warning and message in tooltip like this-------
models.ApplicationUSer.ID hides inherited member
Microsoft.Aspnet.Identity.EntityFramework.IDentity
USer.Id. To make current member override
that implementation, add override keyword otherwise
add new keyword where x is just the namespace.
My StartUp.Auth.cs in App_Start folder is like this------
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager), getUserIdCallback:(id)=>(id.GetUserId<int>()))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
// Uncomment the following lines to enable logging in with third party login providers
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");......................................................................
and my startUp.cs file is like this----
[assembly: OwinStartupAttribute(typeof(WebApp.Startup))]
namespace WebApp
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
}
You will have to pull out your ApplicationUserManager to have it nice and clean and implement more methods... For example see following post (It implemented all methods with your custom Key (TKey in the example):
http://www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.Core/2.0.0-beta1-140211/Release/Default/Microsoft.AspNet.Identity.Core/Microsoft.AspNet.Identity.Core/UserManager.cs?ImageName=Microsoft.AspNet.Identity.Core
You will see that the error you receive GetSecurityStampAsync also is implemented there.

Sending custom parameter on authentication

I'm a servicestack newbie. I'm trying to figure out how to send custom parameter on authentication.
As far as I understood, that's the step to authenticate a client and than execute a set of call within a session
var jsonClient = new JsonServiceClient("http://localhost:55679/");
var authResponse = client.Send(new Authenticate
{
provider = "myProvider",
UserName = "user",
Password = "pwd",
RememberMe = true,
});
var jResponse = jsonClient.Get<CountriesResponse>(request);
Console.WriteLine(jResponse.Countries.Count);
So far so good, I configurated my apphost as following and everything works as expected.
Plugins.Add(new AuthFeature(() => new CustomUserSession(), new IAuthProvider[] {
new MyAuthProvider(),
}));
What should I do if, instead of sending ServiceStack.Authenticate, I'd like to send my MyAuthenticate
request that has same custom properties, somenthing like this?
var authResponse = client.Send(new MyAuthenticate
{
provider = "myProvider",
UserName = "user",
Password = "pwd",
RememberMe = true,
AppId = "AppId",
ProjectId = "ProjectId"
});
My goal is to send custom parameter while I'm authenticating the user, not just those allowed by Authenticate built-in request, and than store those extra parameter within my CustomUserSession.
Thanks
Sending additional info on QueryString or HttpHeaders
As you can't change the built-in Authenticate Request DTO, one way to send additional metadata is to add extra info on the QueryString or HTTP Headers.
If you wanted to use the .NET Service Clients to do this you would need to use the RequestFilter, e.g:
var client = new JsonServiceClient(BaseUrl) {
RequestFilter = req => {
req.QueryString["AppId"] = appId;
req.QueryString["ProjectId"] = appId;
}
};
var authResponse = client.Send(new Authenticate { ... });
Otherwise creating custom Request is often more flexible using ServiceStack's built-in HTTP Utils, e.g:
var url = "{0}/auth/myProvider".Fmt(BaseUrl)
.AddQueryParam("AppId", appId)
.AddQueryParam("ProjectId", projectId);
var authResponse = url.PostJsonToUrl(new Authenticate { ... });
On the server the additional data will be available in the QueryString of the current request which you can get from IServiceBase or IRequest args, e.g:
public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
...
public override IHttpResult OnAuthenticated(IServiceBase authService,
IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo)
{
...
var customSession = (CustomUserSession)session;
customSession.AppId = authService.Request.QueryString["AppId"];
customSession.ProjectId = authService.Request.QueryString["ProjectId"];
return base.OnAuthenticated(authService, session, tokens, authInfo);
}
}
Custom Meta dictionary now available on Authenticate Request DTO
To make this use-case a little easier a new Dictionary<string,string> Meta property was added on the Authenticate DTO which makes calling from the Typed Service Clients a little nicer since you don't have to use a filter, e.g:
var client = new JsonServiceClient(BaseUrl);
var authResponse = client.Send(new Authenticate {
...
Meta = new Dictionary<string, string> { {"AppId", appId}, {"ProjectId", pId} },
});
Which you can access from the Authenticate DTO directly, e.g:
var authRequest = (Authenticate)authService.Request.Dto;
customSession.AppId = authRequest.Meta["AppId"];
customSession.ProjectId = authRequest.Meta["ProjectId"];
The new Meta property is available from v4.0.35+ that's currently available on MyGet.
Use your own Custom Authentication Service
A more disruptive alternative approach to be able to use your own MyAuthenticate DTO is to handle the authentication request in your own Service and then delegate to the AuthService, e.g:
public class MyAuthenticate : Authenticate
{
public string AppId { get; set; }
public string ProjectId { get; set; }
}
public class MyAuthServices : Service
{
public object Any(MyAuthenticate request)
{
using (var auth = base.ResolveService<AuthenticateService>())
{
var response = auth.Post(request);
var authResponse = response as AuthenticateResponse;
if (authResponse != null) {
var session = base.SessionAs<CustomUserSession>();
session.AppId = request.AppId;
session.ProjectId = request.ProjectId;
this.SaveSession(session);
}
return response;
}
}
}

Resources