Where to filter Identity 2.0 claim ticket in a WebAPI app? - asp.net-web-api

ASP.NET apps using OWIN permit multiple Identity sources (Facebook, Google, etc.). Most of the provider-specifc information those sources provide is irrelevant to my app, potentially even large, and I don't want it in my cookies all session. My app is primarily WebAPI, but I suspect the question applies equally to MVC and WebForms.
For now, all I need is an integer account ID. Where/when should I reconstruct the identity, after external authentication?
For example, here is one way I could filter claims:
public ReplaceExistingClaims(ClaimsIdentity identity) {
{
Claim customClaim = GetCustomClaimFromDbForIdentity(identity);
foreach (Claim claim in ClaimsIdentity.Claims) ClaimsIdentity.RemoveClaim(claim);
ClaimsIdentity.AddClaim(customClaim);
}
And following are two different places I could inject those claims changes:
var facebookAuthenticationOptions = new FacebookAuthenticationOptions
{
Provider = new FacebookAuthenticationProvider
{
OnAuthenticated = context =>
{
ReplaceExistingClaims(context.Identity);
return Task.FromResult(0);
}
}
};
Above, I know I can hook an individual provider from Startup IF it provides an Authenticated event. I have two conceptual problems with this. One: it requires me to write and wire up my code separately for each provider I plug in. Two: there is no requirement for providers to provide this event. Both of these make me feel like there must be a different intended insertion point for my code.
public ActionResult ExternalLoginCallback(string returnUrl)
{
ReplaceExistingClaims((ClaimsIdentity)User.Identity);
new RedirectResult(returnUrl);
}
Above, I know I can put code in ExternalLoginCallback. But this happens too late for two reasons. One: The user has already been issued a ticket I consider invalid, but the default [Authorized] considers valid because it's signed by me, and now they are making requests to my site with it. There could even be race conditions here. Two: There is no guarantee the browser will visit this redirect, and I'd prefer from a design perspective if it didn't have to, e.g. to simplify my WebAPI client code.
To the best of my knowledge, the best solution will meet these requirements:
same code applies to all providers
client receives my custom ticket from my server (e.g. without image claims)
client never receives another ticket format from my server
the authentication process requires the minimum possible HTTP round-trips
token-refresh and other core identity features are still available
once a user is [Authorize]d, no further account transformation is necessary
database/repository access is feasible during ticket generation
Some pages I'm researching, for my own notes:
How do I access Microsoft.Owin.Security.xyz OnAuthenticated context AddClaims values?
https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.Facebook/FacebookAuthenticationHandler.cs
https://katanaproject.codeplex.com/workitem/82
https://www.simple-talk.com/dotnet/.net-framework/creating-custom-oauth-middleware-for-mvc-5/

You have to implement DelegationHandler and put all your authentication routines in it.
Register at Application start (DI usage is enabled):
private static void RegisterHandlers(HttpConfiguration config)
{
var authHandler = new MyFacebookAuthHandler();
config.MessageHandlers.Add(authHandler);
}
And this is an example of implementation:
public class MyFacebookAuthHandler : DelegationHandler
{
public override sealed Task<HttpResponseMessage> OnSendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
try
{
// Process credentials
// Probably you have to save some auth information to HttpContext.Current
// Or throw NotAuthorizedException
}
catch(NotAuthorizedException ex)
{
return request.CreateErrorResponse(HttpStatusCode.Unauthorized, ex).ToCompletedTask();
}
catch (Exception ex)
{
return request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex).ToCompletedTask();
}
return base.OnSendAsync(request, cancellationToken);
}
}

The ClaimsAuthenticationManager class is specifically for this.
https://msdn.microsoft.com/en-us/library/system.security.claims.claimsauthenticationmanager(v=vs.110).aspx
Code sample from that reference:
class SimpleClaimsAuthenticatonManager : ClaimsAuthenticationManager
{
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated == true)
{
((ClaimsIdentity)incomingPrincipal.Identity).AddClaim(new Claim(ClaimTypes.Role, "User"));
}
return incomingPrincipal;
}
}

Related

ASP.NET Core Web API: Why need ModelState validation in Get request?

VS 2015 automatically generated the following code:
// GET: api/Companies/5
[HttpGet("{id}")]
public async Task<IActionResult> GetCompany([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Company company = await _context.Companies.SingleOrDefaultAsync(m => m.Id == id);
if (company == null)
{
return NotFound();
}
return Ok(company);
}
What is the point of ModelState validation here?
I'm assuming you used the Web Api template. Since you didn't start from the "Empty" template, VS generated code, that the Microsoft team deemed "good practice".
The point is, that if you want a certain field to contain an email, another to be required, and so on, you might have marked them with data annotations. Now, there's an additional check for those before your method is executed (unnecessary for a simple int, but it's implied that you're likely going to change the arguments). Check this article for more information.
If you find these additions unnecessary, you can always start your project from the Empty template.

aspnet identity; how to login using a legacy password?

i've a site i'm updating to web api with aspnet identity 2.0.
It's a legacy site for which we need to allow the users to use their old passwords; at least during a reasonable migration period
following this article, i've derived a new UserManager from the base UserManager, and set up the PasswordHasher to hash with an old SHA1 algorithm.
My passwordHasher looks like this:
public class SQLPasswordHasher : PasswordHasher
{
public override string HashPassword(string password)
{
string cipherText = EncryptPassword(password);
return cipherText;
}
public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
{
string cipherText = EncryptPassword(providedPassword);
if (cipherText == hashedPassword)
{
return PasswordVerificationResult.SuccessRehashNeeded;
}
else
{
return PasswordVerificationResult.Failed;
}
}
private string EncryptPassword(string plainText)
{
return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(plainText, "sha1");
}
}
When i register users with this code, I can see the passwords are being hashed and persisted in the database correctly... for the password 'foobar', the hashed value is fixed and recognizable, since this algorithm did not use a salt.
However, I cannot log in as these users. If i set a breakpoint in the new hasher, it never gets it. Neither can i seem to hit a breakpoint anywhere in the account controller when trying to log in.
thanks in advance
I'm answering my own question, in the hopes that someone else may benefit.
The problem was, i couldn't find what in the web api service was being called when logging in. I finally realized that something called /Token was being set up as the url to be called in the app.js javascript.
Searching through the project server side sources and googling led me to this article, which pointed me to the ApplicationOAuthProvider.cs file, in the 'Providers' folder of the template application.
The specific line of interest is where the method GrantResourceOwnerCredentials instantiates it's own user manager, thus:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
From there, all i had to do was add this line:
userManager.PasswordHasher = new SQLPasswordHasher();
and i could finally log in.

Domain Driven Design - complex validation of commands across different aggregates

I've only began with DDD and currently trying to grasp the ways to do different things with it. I'm trying to design it using asynchronous events (no event-sourcing yet) with CQRS. Currently I'm stuck with validation of commands. I've read this question: Validation in a Domain Driven Design , however, none of the answers seem to cover complex validation across different aggregate roots.
Let's say I have these aggregate roots:
Client - contains list of enabled services, each service can have a value-object list of discounts and their validity.
DiscountOrder - an order to enable more discounts on some of the services of given client, contains order items with discount configuration.
BillCycle - each period when bills are generated is described by own billcycle.
Here's the usecase:
Discount order can be submitted. Each new discount period in discount order should not overlap with any of BillCycles. No two discounts of same type can be active at the same time on one service.
Basically, using Hibernate in CRUD style, this would look something similar to (java code, but question is language-agnostic):
public class DiscountProcessor {
...
#Transactional
public void processOrder(long orderId) {
DiscOrder order = orderDao.get(orderId);
BillCycle[] cycles = billCycleDao.getAll();
for (OrderItem item : order.getItems()) {
//Validate billcycle overlapping
for (BillCycle cycle : cycles) {
if (periodsOverlap(cycle.getPeriod(), item.getPeriod())) {
throw new PeriodsOverlapWithBillCycle(...);
}
}
//Validate discount overlapping
for (Discount d : item.getForService().getDiscounts()) {
if (d.getType() == item.getType() && periodsOverlap(d.getPeriod(), item.getPeriod())) {
throw new PeriodsOverlapWithOtherItems(...);
}
}
//Maybe some other validations in future or stuff
...
}
createDiscountsForOrder(order);
}
}
Now here are my thoughts on implementation:
Basically, the order can be in three states: "DRAFT", "VALIDATED" and "INVALID". "DRAFT" state can contain any kind of invalid data, "VALIDATED" state should only contain valid data, "INVALID" should contain invalid data.
Therefore, there should be a method which tries to switch the state of the order, let's call it order.validate(...). The method will perform validations required for shift of state (DRAFT -> VALIDATED or DRAFT -> INVALID) and if successful - change the state and transmit a OrderValidated or OrderInvalidated events.
Now, what I'm struggling with, is the signature of said order.validate(...) method. To validate the order, it requires several other aggregates, namely BillCycle and Client. I can see these solutions:
Put those aggregates directly into the validate method, like
order.validateWith(client, cycles) or order.validate(new
OrderValidationData(client, cycles)). However, this seems a bit
hackish.
Extract the required information from client and cycle
into some kind of intermediate validation data object. Something like
order.validate(new OrderValidationData(client.getDiscountInfos(),
getListOfPeriods(cycles)).
Do validation in a separate service
method which can do whatever it wants with whatever aggregates it
wants (basically similar to CRUD example above). However, this seems
far from DDD, as method order.validate() will become a dummy state
setter, and calling this method will make it possible to bring an
order unintuitively into an corrupted state (status = "valid" but
contains invalid data because nobody bothered to call validation
service).
What is the proper way to do it, and could it be that my whole thought process is wrong?
Thanks in advance.
What about introducing a delegate object to manipulate Order, Client, BillCycle?
class OrderingService {
#Injected private ClientRepository clientRepository;
#Injected private BillingRepository billRepository;
Specification<Order> validSpec() {
return new ValidOrderSpec(clientRepository, billRepository);
}
}
class ValidOrderSpec implements Specification<Order> {
#Override public boolean isSatisfied(Order order) {
Client client = clientRepository.findBy(order.getClientId());
BillCycle[] billCycles = billRepository.findAll();
// validate here
}
}
class Order {
void validate(ValidOrderSpecification<Order> spec) {
if (spec.isSatisfiedBy(this) {
validated();
} else {
invalidated();
}
}
}
The pros and cons of your three solutions, from my perspective:
order.validateWith(client, cycles)
It is easy to test the validation with order.
#file: OrderUnitTest
#Test public void should_change_to_valid_when_xxxx() {
Client client = new ClientFixture()...build()
BillCycle[] cycles = new BillCycleFixture()...build()
Order order = new OrderFixture()...build();
subject.validateWith(client, cycles);
assertThat(order.getStatus(), is(VALID));
}
so far so good, but there seems to be some duplicate test code for DiscountOrderProcess.
#file: DiscountProcessor
#Test public void should_change_to_valid_when_xxxx() {
Client client = new ClientFixture()...build()
BillCycle[] cycles = new BillCycleFixture()...build()
Order order = new OrderFixture()...build()
DiscountProcessor subject = ...
given(clientRepository).findBy(client.getId()).thenReturn(client);
given(cycleRepository).findAll().thenReturn(cycles);
given(orderRepository).findBy(order.getId()).thenReturn(order);
subject.processOrder(order.getId());
assertThat(order.getStatus(), is(VALID));
}
#or in mock style
#Test public void should_change_to_valid_when_xxxx() {
Client client = mock(Client.class)
BillCycle[] cycles = array(mock(BillCycle.class))
Order order = mock(Order.class)
DiscountProcessor subject = ...
given(clientRepository).findBy(client.getId()).thenReturn(client);
given(cycleRepository).findAll().thenReturn(cycles);
given(orderRepository).findBy(order.getId()).thenReturn(order);
given(client).....
given(cycle1)....
subject.processOrder(order.getId());
verify(order).validated();
}
order.validate(new OrderValidationData(client.getDiscountInfos(),
getListOfPeriods(cycles))
Same as the above one, you still need to prepare data for both OrderUnitTest and discountOrderProcessUnitTest. But I think this one is better as order is not tightly coupled with Client and BillCycle.
order.validate()
Similar to my idea if you keep validation in the domain layer. Sometimes it is just not any entity's responsibility, consider domain service or specification object.
#file: OrderUnitTest
#Test public void should_change_to_valid_when_xxxx() {
Client client = new ClientFixture()...build()
BillCycle[] cycles = new BillCycleFixture()...build()
Order order = new OrderFixture()...build();
Specification<Order> spec = new ValidOrderSpec(clientRepository, cycleRepository);
given(clientRepository).findBy(client.getId()).thenReturn(client);
given(cycleRepository).findAll().thenReturn(cycles);
subject.validate(spec);
assertThat(order.getStatus(), is(VALID));
}
#file: DiscountProcessor
#Test public void should_change_to_valid_when_xxxx() {
Order order = new OrderFixture()...build()
Specification<Order> spec = mock(ValidOrderSpec.class);
DiscountProcessor subject = ...
given(orderingService).validSpec().thenReturn(spec);
given(spec).isSatisfiedBy(order).thenReturn(true);
given(orderRepository).findBy(order.getId()).thenReturn(order);
subject.processOrder(order.getId());
assertThat(order.getStatus(), is(VALID));
}
Do the 3 possible states reflect your domain or is that just extrapolation ? I'm asking because your sample code doesn't seem to change Order state but throw an exception when it's invalid.
If it's acceptable for the order to stay DRAFT for a short period of time after being submitted, you could have DiscountOrder emit a DiscountOrderSubmitted domain event. A handler catches the event and (delegates to a Domain service that) examines if the submit is legit or not. It would then issue a ChangeOrderState command to make the order either VALIDATED or INVALID.
You could even suppose that the change is legit by default and have processOrder() directly take it to VALIDATED, until proven otherwise by a subsequent INVALID counter-order given by the validation service.
This is not much different from your third solution or Hippoom's one though, except every step of the process is made explicit with its own domain event. I guess that with your current aggregate design you're doomed to have a third party orchestrator (as un-DDD and transaction script-esque as it may sound) that controls the process, since the DiscountOrder aggregate doesn't have native access to all information to tell if a given transformation is valid or not.

Adding profile values for auto-generated user

I'm creating a ASP.NET MVC 3.0 website, and have a couple of different database initializations based on whether the site is intended for development, testing, or production. I'm stuck on the testing initialization, as I'm trying to get a test user created. I can get the user to create just fine, however when I try to add some profile values, I get: System.Web.HttpException: Request is not available in this context. Is there a way to add Profile values in a situation where the request isn't going to be available?
Following code is what is being run:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
if (ApplicationServices.GetInitialCatalog() != "tasktracker")
{
Database.SetInitializer(new TaskTrackerDropCreateDatabaseIfModelChanges());
}
else
{
Database.SetInitializer(new TaskTrackerCreateDatabaseIfNotExists());
}
using (var db = new TaskTrackerContext())
{
db.Database.Initialize(false);
}
}
public class TaskTrackerDropCreateDatabaseIfModelChanges : DropCreateDatabaseIfModelChanges<TaskTrackerContext>
{
protected override void Seed(TaskTrackerContext context)
{
// Set up the membership, roles, and profile systems.
ApplicationServices.InstallServices(SqlFeatures.Membership | SqlFeatures.Profile | SqlFeatures.RoleManager);
// Create the default accounts and roles.
if (ApplicationServices.GetInitialCatalog() == "tasktracker_testing")
{
if (Membership.GetUser("testuser", false) == null)
{
Membership.CreateUser("testuser", "password", "testuser#test.com");
MembershipUser user = Membership.GetUser("testuser", false);
user.IsApproved = true;
var profile = ProfileBase.Create("testuser");
profile.SetPropertyValue("FirstName", "test");
profile.SetPropertyValue("LastName", "user");
profile.SetPropertyValue("TimeZone", "US Mountain Standard Time");
profile.Save();
}
}
}
}
Interesting question. Have you looked at using the new Universal Providers? Dunno if you will run into the same httpcontext issue but may be worth a look: http://www.hanselman.com/blog/IntroducingSystemWebProvidersASPNETUniversalProvidersForSessionMembershipRolesAndUserProfileOnSQLCompactAndSQLAzure.aspx
Did you try to do a call of "Initialize()" :
profile.Initialize(username, true)
after your create action to see if the context should be Initialized.
By using Reflector i saw the ProfileBase of Initialize (see below) creates this kind of context from the settings:
public void Initialize(string username, bool isAuthenticated)
{
if (username != null)
{
this._UserName = username.Trim();
}
else
{
this._UserName = username;
}
SettingsContext context = new SettingsContext();
context.Add("UserName", this._UserName);
context.Add("IsAuthenticated", isAuthenticated);
this._IsAuthenticated = isAuthenticated;
base.Initialize(context, s_Properties, ProfileManager.Providers);
}
It seems working here, the SettingsContext() seems taking account of my custom properties declared in the web.config.
Regards,
I come back again because the solution I added with the "Initialize()" function in fact not run really after an other test. So in fact I found a way which runs correctly.
The problem of "request is not available in this context" in application_start in your case could be due to the application mode "Integrated" which is new from II7 instead of the Classic mode.
To see a good explain you ca go on the Mike Volodarsky's blog IIS7 Integrated mode: Request is not available in this context exception in Application_Start .
I copy/paste an extract which could indicate the main reason:
" *This error is due to a design change in the IIS7 Integrated pipeline that makes the request context unavailable in Application_Start event. When using the Classic mode (the only mode when running on previous versions of IIS), the request context used to be available, even though the Application_Start event has always been intended as a global and request-agnostic event in the application lifetime. Despite this, because ASP.NET applications were always started by the first request to the app, it used to be possible to get to the request context through the static HttpContext.Current field.* "
To solve this you can use a workaround that moves your first-request initialization from Application_Start to BeginRequest and performs the request-specific initialization on the first request.
A good example of code is done in his blog :
void Application_BeginRequest(Object source, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
HttpContext context = app.Context;
// Attempt to peform first request initialization
FirstRequestInitialization.Initialize(context);
}
class FirstRequestInitialization
{
private static bool s_InitializedAlready = false;
private static Object s_lock = new Object();
// Initialize only on the first request
public static void Initialize(HttpContext context)
{
if (s_InitializedAlready)
{
return;
}
lock (s_lock)
{
if (s_InitializedAlready)
{
return;
}
// Perform first-request initialization here
//
// You can use your create profile code here....
//---
s_InitializedAlready = true;
}
}
}

GWT - Handling events from underlying widgets in EntryPoint

I have searched the web for the correct answer, but I've been failing to achieve this :
In EntryPoint class, I need to manage widgets according to events that occur in nested widgets. I've cleaned of the code to focus only on what is important here.
I have built a few UiBinder widgets, for example, a Login pane where the user can enter his credentials. In my EntryPoint class, I add the widgets in the correct position.
// This is from EntryPoint class
public void onModuleLoad() {
LoginPane lp = new LoginPane();
RootPanel.get("headerRightPane").add(lp);
lp.setFocus();
// Other widgets added in same manner after this point...
}
I would like a successful login to remove the LoginPane and replace it by another widget (AccountPane) that would show the account information for the user that is logged in. I have an onClick event, in LoginPane, that sends a request to a fully functional Servlet that checks the credentials. At this exact point, if the Servlet determines that the login is indeed successful, I would like to fire a "successfulLogin" event (from LoginPane) that could notify the EntryPoint class that the LoginPane can now be replaced by the AccountPane.
// This is from LoginPane class
#UiHandler("loginButton")
void onClick(ClickEvent e) {
checkCredentials(usernameField.getText(), passwordField.getText());
}
public void checkCredentials(String username, String password) {
String usernameToServer = username;
String passwordToServer = password;
credentialsService.credentialsServer(usernameToServer, passwordToServer,
new AsyncCallback<CredentialsPaneContent>() {
public void onFailure(Throwable caught) {
answerLabel.setText(Utilities.SERVER_ERROR);
}
public void onSuccess(CredentialsPaneContent result) {
if ( result == null ) {
answerLabel.setText("Login Failed.");
} else {
// Fire event here (to be caught by EntryPoint class)
answerLabel.setText("Login Successful.");
}
}
});
}
So, the question : How should I proceed to create, fire and listen to the event from my nested widget?
Use an EventBus. Additionally, consider adopting the Model-View-Presenter pattern to keep your application maintainable as it grows:
Large scale application development and MVP, Part I
Large scale application development and MVP, Part II
GWT MVP Development with Activities and Places
Lets have an interface which is implemented by EntryPoint class,
now have a referrence of interface type which actually an object of interface.
Using this interface referrence invoke the listner(interface) mothod, which serves your purpose.

Resources