I am implementing OWIN authentication on a mysql backend, I dont thnk thats a problem as my registration work pretty well. I have basically worked off this post (i.e. nicked most of the code).
I am also using DI via autofac so I have changed a few things around to inject dependencies into the SimpleAuthorizationServerProvider
THE PROBLEM
I post grant_type=password, username and password to http://localhost/myappurl/token and I get back "error":"invalid_client". I get no hits when I try to debug so its probably failing in the library and not getting to my own code. Does anyone know why this would be?
Please pardon the lengthy code, I have no idea where the issue could be so I have posted everything I think is relevant, if anyone needs to see more code, please ask.
SimpleAuthorizationServerProvider
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
private readonly IUserService _userService;
public SimpleAuthorizationServerProvider(IUserService userService)
{
_userService = userService;
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var authenticate = await _userService.FindUser(context.UserName, context.Password);
if (!authenticate)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
Startup
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app, (IOAuthAuthorizationServerProvider)config.DependencyResolver.GetService(typeof(IOAuthAuthorizationServerProvider)));
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app, IOAuthAuthorizationServerProvider provider)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(90),
Provider = provider,
ApplicationCanDisplayErrors=true,
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
IocConfig
public static class IocConfig
{
public static void Register(HttpConfiguration config)
{
var builder = new ContainerBuilder();
// Configure the container
// Register individual components
builder.Register(c => new MySQLContext()).As<IMySqlContext>().InstancePerRequest();
builder.RegisterType<SimpleAuthorizationServerProvider>().As<IOAuthAuthorizationServerProvider>();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
}
You have a lot of code there, so it's not easy to isolate the problem. As a first step, consider removing the code for Autofac DI and see if that makes any difference. It's hard to tell what the problem might be otherwise.
If the issue is indeed related to the DI code, then perhaps this should be a raised as a separate question. In that case, try to create a small code example that demonstrates the issue succinctly. People are more likely to help if the problem code is short and to the point.
Make sure that you've set up SSL for your site. I had a similar issue and the problem was that I was not using SSL.
Related
I'm using Ninject in a new Azure WebJobs project. One of my repositories requires a Db client to be passed. How do I pass this client?
My bindings class is:
public class NinjectBindings : Ninject.Modules.NinjectModule
{
public override void Load()
{
Bind<IMyRepository>().To<MyRepository>();
}
}
My Main function in the console app looks like this:
static void Main()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
var config = new Configuration();
config.AddJsonFile("appsettings.json");
DbClient _dbClient = new DbClient(config);
IMyRepository myRepository = kernel.Get<IMyRepository>(); // This is where I get an error
}
My repository code is like this which is expecting the DbClient
public class MyRepository : IMyRepository
{
private DbClient _client;
public MyRepository(DbClient client)
{
_client = client;
}
}
You need to setup a binding for your DbClient.
I'd suggest being cautious around when components are released. I've not seen a good ninject example for web jobs yet so I've wired up manually. But that's just my thoughts...
I need an instance of IDataProtectionProvider to generate email confirmation tokens using the Identity Framework UserManager in an Azure Web Jobs worker:
var confirmToken = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
This crashes because a null IUserTokenProvider<User, int> was passed to the UserManager<User, int> upon constuction.
In the MVC application an instance is created like this:
public class OWINStartup
{
public void Configuration(IAppBuilder app)
{
var dataProtectionProvider = app.GetDataProtectionProvider();
But of course, Azure Web Jobs doesn't have an OWINStartup hook. Any advice?
Taking a look at the Katana source code for the OWIN startup context you can see the default implementation of the DataProtectionProvider is a MachineKeyDataProtectionProvider. Unfortunately this class is not exposed to us, only the DpapiDataProtectionProvider which will not work when hosted in azure.
You can find the implementation of the MachineKeyDataProtectionProvider here. You will need to also implement your own MachineKeyDataProtector as seen here. These are not difficult implmentations and are essentially wrappers around MachineKey.Protect() and MachineKey.Unprotect().
The implementation for MachineKeyDataProtectionProvider and MachineKeyDataProtector from the Katana project source (apache 2.0 license):
internal class MachineKeyProtectionProvider : IDataProtectionProvider
{
public IDataProtector Create(params string[] purposes)
{
return new MachineKeyDataProtector(purposes);
}
}
internal class MachineKeyDataProtector : IDataProtector
{
private readonly string[] _purposes;
public MachineKeyDataProtector(string[] purposes)
{
_purposes = purposes;
}
public byte[] Protect(byte[] userData)
{
return MachineKey.Protect(userData, _purposes);
}
public byte[] Unprotect(byte[] protectedData)
{
return MachineKey.Unprotect(protectedData, _purposes);
}
}
Once you have that implemented it is easy to plug into the UserManager:
var usermanager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>());
var machineKeyProtectionProvider = new MachineKeyProtectionProvider();
usermanager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(machineKeyProtectionProvider.Create("ASP.NET Identity"));
Hope that helps get you in the right direction.
I have an extremely odd error and wondered if anyone knew the reason for this.
When I create a new DataObject and TableController called Content and ContentController respectively, it doesn't register the tablecontroller and the help documentation it automatically generates has lost its styling.
I can't connect to the controller at all but all other controllers work as expected.
If I just rename it to DataController and that's just the name of the controller, not the dataobject everything works perfectly.
Is ContentController a reserved word of some kind or is this just specifically happening on my machine?
public class DataController : TableController<Content>
{
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
MobileContext context = new MobileContext();
DomainManager = new EntityDomainManager<Content>(context, Request, Services);
}
// GET tables/Content
public IQueryable<Content> GetAllContent()
{
return Query();
}
// GET tables/Content/48D68C86-6EA6-4C25-AA33-223FC9A27959
public SingleResult<Content> GetContent(string id)
{
return Lookup(id);
}
// PATCH tables/Content/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task<Content> PatchContent(string id, Delta<Content> patch)
{
return UpdateAsync(id, patch);
}
// POST tables/Content/48D68C86-6EA6-4C25-AA33-223FC9A27959
public async Task<IHttpActionResult> PostContent(Content item)
{
Content current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
// DELETE tables/Content/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task DeleteContent(string id)
{
return DeleteAsync(id);
}
}
An MVC project will create an application directory called Content. This will override your route mapping to the ContentController.
You can get around this if desired through changing RouteMaps and other trickery although probably the simpliest answer is to change the name of the controller...
Im new to dependency injection and Ive decided to use autofac as it seems to have the best 'out of the box' support for MVC5 (others might be better but im a newbie to this)
Im creating simple use scenarios and from the wiki ive got the following code in application_start in global.asax
protected void Application_Start()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<ArtistController>().InstancePerHttpRequest();
builder.RegisterType<ArtistService>().As<IArtistService>().SingleInstance();
builder.RegisterType<ArtistRepository>().As<IArtistRepository>().SingleInstance();
builder.RegisterType<BandMemberRepository>().As<IBandMemberRepository>).SingleInstance();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
and in my ArtistController I have this
private IArtistService _artistService;
I then have some code the retrieves and updates data, all very simple. This works ok and Im starting to get my head around the whole concept.
My question is this, do I have to register all the concrete classes Im using manually ? My app could eventually grow and I would have many, many classes so this will be a pain to manage. I did come across this
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
which as far as Im aware should register everything for me but it didnt work. Am I doing something wrong ?
ok, thanks for the advice.
the autofac website shows an example using lambdas, so I added this in global.asax
builder.RegisterAssemblyTypes(typeof(MvcApplication).Assembly)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(MvcApplication).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces();
but that didnt work, any idea why ?
I do most (90+%) of my registrations by tagging them with this attribute:
[AttributeUsage(AttributeTargets.Class)]
[JetBrains.Annotations.MeansImplicitUse]
public class AutoRegisterAttribute : Attribute {}
Then I use this module to register those classes:
public class AutoRegisterModule : Module
{
private readonly Assembly[] _assembliesToScan;
public AutoRegisterModule(params Assembly[] assembliesToScan)
{
_assembliesToScan = assembliesToScan;
}
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(_assembliesToScan)
.Where(t => t.GetCustomAttribute<AutoRegisterAttribute>(false) != null)
.AsSelf()
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
}
public static AutoRegisterModule ForCallingAssembly()
{
return new AutoRegisterModule(Assembly.GetCallingAssembly());
}
}
So when I'm building my container, I typically just do:
builder.RegisterModule(AutoRegisterModule.ForCallingAssembly());
Looking at the ServiceStack.UseCases example project. I am trying to use the jsonserviceclient to call the HelloRequest service after I have called the authentication service. No matter what I do it appears to be failing and returning the Not Found error message. Anyone know what I am doing wrong?
protected void Button1_Click(object sender, EventArgs e)
{
var baseUrl = Request.Url.GetLeftPart(UriPartial.Authority) + "/api";
var client = new JsonServiceClient(baseUrl);
client.UserName = "admin";
client.Password = "123";
client.SetCredentials("admin", "123");
client.AlwaysSendBasicAuthHeader = true;
client.Send(new HelloRequest { Name = "Mike" });
}
The server has the service configured like
public class AppHost : AppHostBase
{
public AppHost() : base("Custom Authentication Example", typeof(AppHost).Assembly) { }
public override void Configure(Container container)
{
// register storage for user sessions
container.Register<ICacheClient>(new MemoryCacheClient());
// Register AuthFeature with custom user session and custom auth provider
Plugins.Add(new AuthFeature(
() => new CustomUserSession(),
new[] { new CustomCredentialsAuthProvider() }
));
}
}
What I would really like is a good solution to the following problem I have. I have an existing system with an existing user database and custom authentication process. I am now trying to expose the functions of the system as web services using servicestack. I program using bog standard webforms so the MVC examples dont work too well for me. I am just looking for the best solution for my particular scenario where I can authenticate callers to my webservice with the majority of my clients using webforms in .NET
You also need to have Basic Auth enabled on the server you're trying to authenticate with.
See the SocialBootstrapApi AppHost for an example:
Plugins.Add(new AuthFeature(
() => new CustomUserSession(), //Use your own typed Custom UserSession type
new IAuthProvider[] {
new BasicAuthProvider(), //Sign-in with Basic Auth
}));