I've successfully implemented oAuth using OWIN in my WebApi 2 Server with:
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions {
TokenEndpointPath = new PathString("/api/TokenByPassword"),
// ...
});
However, I would like the TokenEndpointPath to be dynamic as I will have multiple databases each with their own account records.
I believe I want something like:
TokenEndpointPath = new PathString("/api/{databaseid}/TokenByPassword");
I don't believe OAuthAuthorizationServerOptions supports this and even if it did - how would I get the databaseid ?
I could implement this in my own WebAPI with AttributeRouting, but then what would be the correct OWIN calls to make in that WebAPI to generate the correct BearerToken?
I found the answer..
Even though the TokenEndpointPath is specified in the OAuthAuthorizationServerOptions, the OAuthAuthorizationServerProvider has a delegate called OnMatchEndpoint. Inside this delegate, you can access the Request.Uri.AbsolutePath of the call and if it matches your criteria, you can then call MatchesTokenEndpoint() in which case OnGrantResourceOwnerCredentials will get called where you again can gain access the the Request.Uri and pick out the {databaseid} and use the correct database to Grant access.
OWIN is very flexible, but not immediately obvious which calls to make when to do what you want when it is something not quite straightforward.
Just to make it clearer, here is the implementation of the function MatchEndpoint of the class that extend OAuthAuthorizationServerProvider, as suggested by David Snipp :
private const string MatchTokenUrlPattern = #"^\/([\d\w]{5})\/token\/?$";
public override async Task MatchEndpoint(OAuthMatchEndpointContext context)
{
var url = context.Request.Uri.AbsolutePath;
if (!string.IsNullOrEmpty(url) && url.Contains("token"))
{
var regexMatch = new Regex(MatchTokenUrlPattern).Match(url);
if (regexMatch.Success)
{
context.MatchesTokenEndpoint();
return;
}
}
await base.MatchEndpoint(context);
}
Be careful on what you do in there because it is called at every request.
Related
In my Azure Mobile .NET backend I want to use Azure Mobile .NET Server Swagger . I'm looking for fast way to hide swagger UI from public access ? Is there any way to provide access only for selected users ?
First a disclaimer: Even if you protect your Swagger UI from public consumption, you are not protecting your APIs from public consumption. You have to assume that everyone knows all of your routes and have the appropriate security in place to protect any requests that may come in.
That being said, there's still not a simple way to do this. Swashbuckle (the piece that adds Swagger to Web API) adds a custom HttpMessageHandler to the /swagger/ui route (as seen here). If you look at the Web API pipeline, you can see that if you specify a custom handler, you can bypass all of the Controller selection, Auth filters, etc. This is what happens here.
Some solutions:
Use an app setting to conditionally call ConfigureSwagger(config) in debug modes only. This would prevent all /swagger routes from making it into production. Or you could use a staging slot and only add it there.
You can wrap the SwaggerUiHandler with something like this Basic Auth MessageHandler. This would prompt the user for basic creds if they went to the /swagger/ui route. See below for my modified version of this code.
Maybe with a little more thought we can come up with a better solution -- I see a couple of issues (here and here) in the Swashbuckle repo that indicate you're not the first one to hit this.
Modified BasicAuthHandler (from here):
Warning: minimally tested (and be sure to change how you verify user/pass)
public class BasicAuthMessageHandler : DelegatingHandler
{
private const string BasicAuthResponseHeader = "WWW-Authenticate";
private const string BasicAuthResponseHeaderValue = "Basic";
public BasicAuthMessageHandler(HttpMessageHandler innerHandler)
{
this.InnerHandler = innerHandler;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
AuthenticationHeaderValue authValue = request.Headers.Authorization;
HttpResponseMessage unauthorizedResponse = request.CreateUnauthorizedResponse();
if (authValue != null && !string.IsNullOrWhiteSpace(authValue.Parameter))
{
Credentials parsedCredentials = ParseAuthorizationHeader(authValue.Parameter);
if (parsedCredentials != null)
{
// TODO: Check that the user/pass are valid
if (parsedCredentials.Username == "user" &&
parsedCredentials.Password == "pass")
{
// If match, pass along to the inner handler
return base.SendAsync(request, cancellationToken);
}
}
}
else
{
// Prompt for creds
unauthorizedResponse.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
}
return Task.FromResult(unauthorizedResponse);
}
private Credentials ParseAuthorizationHeader(string authHeader)
{
string[] credentials = Encoding.ASCII.GetString(Convert
.FromBase64String(authHeader))
.Split(
new[] { ':' });
if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0])
|| string.IsNullOrEmpty(credentials[1])) return null;
return new Credentials()
{
Username = credentials[0],
Password = credentials[1],
};
}
}
Registering with Swagger route
// Do this after calling ConfigureSwagger
ConfigureSwagger(config);
// Remove the swagger_ui route and re-add it with the wrapped handler.
var route = config.Routes["swagger_ui"];
config.Routes.Remove("swagger_ui");
config.Routes.MapHttpRoute("swagger_ui", route.RouteTemplate, route.Defaults, route.Constraints, new BasicAuthMessageHandler(route.Handler));
I am using the Change Password functionality that visual studio generated for the accountcontroller. I am able to change the password without errors but when I go to login using the new password, I get a login error but if I use the old password, it works.
If I restart the app then the newly changed password takes effect. I am also using Autofac, may be I am not configuring the container correctly.
var builder = new ContainerBuilder();
builder.Register(c => new ApplicationDataContext(connectionString)).InstancePerLifetimeScope();
builder.RegisterType<ApplicationUserManager>().AsSelf();
builder.RegisterType<ApplicationRoleManager>().AsSelf();
builder.Register(c => new UserStore<ApplicationUser>(c.Resolve<ApplicationDataContext>())).AsImplementedInterfaces();
builder.Register(c => new RoleStore<IdentityRole>(c.Resolve<ApplicationDataContext>())).AsImplementedInterfaces();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>();
builder.Register(c => new IdentityFactoryOptions<ApplicationUserManager>
{
DataProtectionProvider = new DpapiDataProtectionProvider("Application")
});
builder.Register(c => new ApplicationOAuthProvider(publicClientId, c.Resolve<ApplicationUserManager>())).As<IOAuthAuthorizationServerProvider>();
Any help will be much appreciated.
Thanks
--------UPDATED----------
ContanierConfig.cs
public static void Configure(HttpConfiguration config)
{
// Configure the application for OAuth based flow
const string publicClientId = "self";
// ContainerConfig Config
var connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
var elasticsearchUrl = ConfigurationManager.AppSettings["ElasticSearchUrl"];
var elasticSearchName = ConfigurationManager.AppSettings["ElasticSearchName"];
var builder = new ContainerBuilder();
builder.Register(c => new BimDataContext(connectionString)).InstancePerRequest();
builder.RegisterType<ApplicationUserManager>().AsSelf().InstancePerRequest();
builder.RegisterType<ApplicationRoleManager>().AsSelf().InstancePerRequest();
builder.Register(c => new UserStore<ApplicationUser>(c.Resolve<BimDataContext>())).AsImplementedInterfaces().InstancePerRequest();
builder.Register(c => new RoleStore<IdentityRole>(c.Resolve<BimDataContext>())).AsImplementedInterfaces().InstancePerRequest();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>().InstancePerRequest();
builder.Register(c => new IdentityFactoryOptions<ApplicationUserManager>
{
DataProtectionProvider = new DpapiDataProtectionProvider("Application")
}).InstancePerRequest(); ;
builder.RegisterType<SimpleRefreshTokenProvider>().As<IAuthenticationTokenProvider>().InstancePerRequest();
builder.RegisterType<AuthRepository>().As<IAuthRepository>().InstancePerRequest();
builder.Register(c => new ApplicationOAuthProvider(
publicClientId,
c.Resolve<ApplicationUserManager>(),
c.Resolve<IAuthRepository>()))
.As<IOAuthAuthorizationServerProvider>().InstancePerRequest();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();
// UoW registration: being explicit
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();
// Repositories registration
builder.RegisterAssemblyTypes(typeof(ClientRepository).Assembly)
.AsImplementedInterfaces()
.InstancePerRequest();
// Services registration
builder.RegisterAssemblyTypes(typeof(ClientService).Assembly)
.AsImplementedInterfaces()
.InstancePerRequest();
builder.RegisterAssemblyTypes(typeof(ClientSearchService).Assembly)
.AsImplementedInterfaces()
.InstancePerRequest();
builder.RegisterType<IfcFileImportTask>().As<IIfcFileImportTask>().InstancePerRequest();
builder.RegisterType<COBieFileImportTask>().As<ICOBieFileImportTask>().InstancePerRequest();
// Hangfire registration
builder.RegisterType<BackgroundJobClient>().As<IBackgroundJobClient>().InstancePerRequest();
// OPTIONAL: Register the Autofac filter provider.
builder.RegisterWebApiFilterProvider(config);
// Set the dependency resolver to be Autofac.
var container = builder.Build();
JobActivator.Current = new AutofacJobActivator(container);
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
Startup.Auth.Cs
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// Configure the db context and user manager to use a single instance per request
//app.CreatePerOwinContext(BimDataContext.Create);
//app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.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
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
var oAuthAuthorizationServerProvider = GlobalConfiguration.Configuration.DependencyResolver.GetRequestLifetimeScope().Resolve<IOAuthAuthorizationServerProvider>();
var authenticationTokenProvider = GlobalConfiguration.Configuration.DependencyResolver.GetRequestLifetimeScope().Resolve<IAuthenticationTokenProvider>();
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = oAuthAuthorizationServerProvider,
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(5),
RefreshTokenProvider = authenticationTokenProvider,
// In production mode set AllowInsecureHttp = false,
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
Getting error
"value cannot be null. parameter name context autofac" on line var oAuthAuthorizationServerProvider = GlobalConfiguration.Configuration.DependencyResolver.GetRequestLifetimeScope().Resolve<IOAuthAuthorizationServerProvider>();
I was missing a key component of oauth2, the solution to this problem is refresh_tokens. On change password, invalidate the refresh token and force user to log out.
http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/
If using ASP.NET (this includes MVC and Web API, Web Forms, etc) and AutoFac you should register all your components using the extension method .InstancePerRequest(). The only exception is for components that are thread safe and where you do not have to worry about errors/unexpected results occurring from one request accessing the same (stale) data as another. An example might be a Factory or a Singleton.
Example of use on a line of code:
builder.Register(c => new UserStore<ApplicationUser>(c.Resolve<ApplicationDataContext>())).AsImplementedInterfaces().InstancePerRequest();
This ensures that every new incoming Http Request will get its own copy of that implementation (resolved and injected hopefully via an interface). Autofac will also cleanup the Disposable instances at the end of each request.
This is the behavior you need. It ensures that there is no cross request interference (like one request manipulating data on a shared dbcontext on another request). It also ensures that data is not stale as it is cleaned up after each request ends.
See the Autofac documentation for more details (here an excerpt).
Instance Per Request
Some application types naturally lend themselves to “request” type semantics, for example ASP.NET web forms and MVC applications. In these application types, it’s helpful to have the ability to have a sort of “singleton per request.”
Instance per request builds on top of instance per matching lifetime scope by providing a well-known lifetime scope tag, a registration convenience method, and integration for common application types. Behind the scenes, though, it’s still just instance per matching lifetime scope.
Changing your DI definitions above to include this should resolve your issues (I think based on what you have provided). If not then it might be a problem with your Identity registration in which case you should post that code so it can be scrutinized.
I have created a Xamarin where I want to query one database on a Azure SQL Server and regarding which result I get back I want to query one of X numbers of certain databases.
So far I have been able to create two different APIs where the first API gets information from the first database.
And I have hardcoded (in the TableController) to use one specific database (in the same SQL Server).
string dbString = "database2";
myContextClass context = new myContextClass(dbString);
This works like a charm. However. I would like to be able to pass which database I want to connect to from my app.
I.e. when calling my mobileservice all I do is this:
this.client = new MobileServiceClient(
Constants.DatabaseURL);
Is there something I can add to this methodcall that will set the database connectionstring in the controller?
You should not be connecting to the database from the mobile App, you should have a backend REST service built for example using Web API and hosted in Azure API Service, this is where the connection to the database will occur, and the connection string will be added to the web.config file which can be easily changed from the Azure portal.
I think you need 2 dbContext instances. Here is an example in the controller how to initialize 1 dbContext. So, I guess, you could have the parameter you want to specify which db you want, and use the main controller or call another controller which is initialized with the other dbContext. (or try overwriting the DomainManager with different context)
public class TodoItemController : TableController<TodoItem>
{
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
AppContext context = new AppContext();
DomainManager = new EntityDomainManager<TodoItem>(context, Request);
}
// GET tables/TodoItem
public IQueryable<TodoItem> GetAllTodoItems()
{
return Query();
}
Then you have 2 dbContext instances like this:
public class AppContext : DbContext
{
private const string connectionStringName = "Name=MS_TableConnectionString";
public NeptuneAppContext() : base(connectionStringName)
{
}
where you can specify different connectionStrings.
Hope it helps
I'd like (through app/web configuration perhaps) to change the cache client used in my ServiceStack application, during runtime.
For example, I have this currently:
container.Register<ICacheClient>(new MemoryCacheClient());
I'd like at runtime to change this to a Redis ICacheClient usage. What if I had two containers registered (one Memory and on Redis). Is it possible to switch between containers at runtime in a call like this in my service:
public object Get(FooRequest request)
{
string cacheKey = UrnId.CreateWithParts("Foo", "Bar");
return RequestContext.ToOptimizedResultUsingCache(base.Cache, cacheKey, sCacheDuration, () =>
{
return TestRepository.Foos;
});
}
EDIT:
Note, after more research, if you have more than one ICacheClient registered:
container.Register<IRedisClientsManager>(c => new PooledRedisClientManager("localhost:6379"));
container.Register(c => c.Resolve<IRedisClientsManager>().GetCacheClient());
container.Register<ICacheClient>(new MemoryCacheClient());
Then accessing base.Cache within your service will return the most recent ICacheClient that was registered... ie: in the case above, MemoryCacheClient.
So with the ability to access the Cache object from within the service, I'd just need a way to get a particular Cache from my registered caches, which I can't see any property for.
Doing something like this would allow you to register different providers with the container based on a web config setting:
var redisCacheString = ConfigurationManager.AppSettings["UseRedis"];
var useRedis = false;
if (!bool.TryParse(redisCacheString, out useRedis))
{
container.Register<IRedisClientsManager>(c => new PooledRedisClientManager("localhost:6379"));
container.Register(c => c.Resolve<IRedisClientsManager>().GetCacheClient());
}
else
{
container.Register<ICacheClient>(new MemoryCacheClient());
}
Hope that helps!
It seems to me that you'll need more flexibility rather than just a simple registration on the composite root, you can try to implement the composite pattern in your container registration.
steven explains this pattern using simple injector but I think it can be implemented with the IOC provided OOB by SS or any other
I hope that helps
My problem is...
...I have a DTO like this
[Route("/route/to/dto/{Id}", "GET")]
public class Foo : IReturn<Bar>
{
public string Id { get; set; }
}
and need to call the service that implements the method with this signature
public Bar Get(Foo)
from a request and/or response filter. I don't know what class implements it (don't want to need to know). What I need is something like the LocalServiceClient class in the example below:
var client = new LocalServiceClient();
Bar bar = client.Get(new Foo());
Does this LocalServiceClient thing exists? JsonServiceClient has a pretty similar interface, but using it would be inneficient (I need to call my own service, I shouldn't need an extra round-trip, even to localhost, just to do this).
I'm aware of ResolveService method from Service class, but it requires me to have a service instance and to know what class will handle the request.
I think this LocalServiceClient is possible because I have all the data that a remote client (e.g. JsonServiceClient) needs to call the service - request DTO, route, verb - but couldn't find how to do it. Actually, it should be easier to implement than JsonServiceClient.
JsonServiceClient would do it, but there must be a better way, using the same request context.
What I want to do (skip this if you're not curious about why I'm doing this)
Actually, my DTOs are like this:
[EmbedRequestedLinks]
[Route("/route/to/dto/{Id}", "GET")]
public class MyResponseDto
{
public string Id { get; set; }
public EmbeddableLink<AResponseDto> RelatedResource { get; set; }
public EmbeddableLink<AnotherResponteDto> AnotherRelatedResource { get; set; }
}
EmbedRequestedLinksAttribute is a request/response filter. This filter checks if there is a query argument named "embed" in the request. If so, the filter need to "embed" the comma-separated related resources referenced by the argument into the response to this request. EmbeddableLink<T> instances can be obtained by using extension methods like these:
1) public static EmbeddableLink<T> ToEmbeddableLink<T>(this IReturn<T> requestDto)
2) public static EmbeddableLink<T> ToEmbeddableLink<T>(this T resource)
Assume a client places this request:
GET /route/to/dto/123456?embed=relatedResource HTTP/1.1
The service that will handle this request will return an instance of MyResponseDto with EmbeddableLinks created using signature (1). Then my response filter will see the embed query argument and will call the Get method of the appropriate service, replacing the RelatedResource with another instance of EmbeddableLink, this time created using extension method (2):
var client = new LocalServiceClient();
response.RelatedResource = client.Get(response.RelatedResource.RequestDto)
.ToEmbeddableLink();
The serialization routine of EmbeddableLink takes care of the rest.
In case an embeddable link is not included in the embed list the serialization routine will call the extension method ToUrl (provided by ServiceStack), that takes a verb and converts a request DTO into a URL. In this example the client will get this response:
{
"id": "9asc09dcd80a98",
"relatedResource": { "id": "ioijo0909801", ... },
"anotherRelatedResource":
{
"$link": { "href": "/route/to/another/dto/1sdf89879s" }
}
}
I know the creators of ServiceStack think that polymorphic request/responses are bad things but this case seems OK to me because I'm not creating services, instead I'm extending the framework to help me create services the way I (and possibly other users of ServiceStack) need. I'm also creating other hypermedia extensions to ServiceStack. (I hope my boss allow me to publish these extensions on github)
If you really want to do this then look the source code for ServiceStack. Look at the ServiceManager and ServiceController. These classes are responsible for registering and resolving services. You might even be able to use reflection to create services on the fly with the static EndpointHost.Metadata like so:
var operation = EndpointHost.Metadata.Operations
.FirstOrDefault(x => x.RequestType == typeof(Person));
if (operation != null)
{
var svc = Activator.CreateInstance(operation.ServiceType);
var method = operation.ServiceType.GetMethod("Get");
var response = method.Invoke(svc, new[] { new Person() });
}
This kinda works but you will get NULL exceptions if there is other code calling
var httpRequest = RequestContext.Get<IHttpRequest>();
But I would not suggest this.
Instead if you create your own Business Service classes that do all the CRUD operations (POST/PUT/GET ect). Then make the ServiceStack Services thin wrappers over them. Now you can call your own services whenever you want without worrying about the HTTP Request and ServiceStack. Only use the ServiceStack Service when you are dealing with HTTP requests
You can call the static AppHostBase.Resolve() method as demonstrated here, calling a SeviceStack Service from an MVC controller:
var helloService = AppHostBase.Resolve<HelloService>();
helloService.RequestContext = System.Web.HttpContext.Current.ToRequestContext();
var response = (HelloResponse)helloService.Any(new HelloRequest { Name = User.Identity.Name });
However, I would take #kampsj's approach of making your ServiceStack services a thin wrapper around your application service classes and only deal with HTTP/Session specific stuff in the ServiceStack service.