ASP.NET MVC: Authenticating a user without creating the user - asp.net-mvc

I am creating an MVC 5 application that authenticates a user via Facebook to access a particular resource.
I want to be able to authenticate this user with a cookie as if they are logged into my site as an authenticated user manually.
However, it is a requirement that this user not be actually created as a user in the membership system used by the site, as it is reserved for admins.
Is this possible?
I attempted to do this by creating an identity manually but this was a total hack attempt by piecing together the existing code from the MVC Account controller...
var authUser = new ApplicationUser() { UserName = me.email, Email = me.email };
var manager = HttpContext.GetOwinContext().Authentication;
manager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
manager.SignIn(new AuthenticationProperties() { IsPersistent = true }, await HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>().CreateIdentityAsync(authUser, DefaultAuthenticationTypes.ApplicationCookie));
It almost seems to work, but then it complains that the user id does not exist.
Which I assume means it's attempting to use my user database to authenticate the user, which as I said is not what we want.
So is it possible to manually authenticate a user with the custom default asp.net account implementation and persist an authenticated cookie, but NOT create an actual user?
please let me know what more info I could provide to help find a solution. thank you

shortly after submitting this I found this question: Storing/Retrieving user data without database when using OWIN cookie authentication
which seems to do exactly what I need, indeed this did the trick, thanks and sorry for duplicating the question

Related

How to use external login provider with a custom user store?

I am developing an ASP.NET MVC 5 Web application that allows user to authenticate using an external provider.
In Internet there are a lot of information teaching how to enable external login providers, but none teaches how to actually authenticate the user in the system when login returns to the MVC site. All information I have found assumes developer is using the default ASP.NET identity user store, so it tells nothing about what to do next.
For example, in Google, when user selects the Google account, the call returns to the site and run the method FindAsync of the custom user store, but, after that, how can I actually log the user in?
This is one my attempts to retrieve the user e-mail:
public Task<T> FindAsync(UserLoginInfo login)
{
var info = AuthenticationManager.GetExternalLoginInfoAsync().Result;
var emailClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email);
}
But GetExternalLoginInfoAsync does not belong to AuthenticationManager object.
I have read that Microsoft.AspNet.Identity.Owin should be included, but in my case, that NuGet package is already included, and of course, the corresponding using statement is present in the code.
Any help, please?

Spring security with login with amazon

We had an application that uses basic auth (user and password), we created the roles in the Database and it worked perfectly.
Now we are migrating to use Login With Amazon and we will also add Login With Facebook.
Is there an easy way to keep our current Spring Security architecture (I do not need the user password anymore though, I would like to keep the roles) and add support to Login With Amazon.
I noticed there is this project for Spring Security with oAuth2 http://projects.spring.io/spring-security-oauth/ It is not clear to me what this does.
The documentation for Spring oAuth is pretty bad, but the examples they provide are workable if you know your way around Spring Security.
I want to to flag here that using oAuth 2 for user authentication isn't recommended and that you should stick to providers that support Open ID Connect. It is not clear to me from a quick glance at Login With Amazon if it's OIDC or just plain oAuth2, but either way you can use their SDK to achieve what you're looking for.
It is definitely possible to use Spring oAuth to set up login over oAuth 2, and probably OIDC as well, but I always end up rolling my own solution because I find it simpler.
I'm going to focus on Login with Amazon here, but login with Facebook should be fairly similar.
There are four things you need to do:
Add Amazon login to your website
Implement support for storing a user's external ID in the user profile
Implement a controller for handling JWT tokens and "logging in" the user
Call the new controller once the user has logged in
The first one should be fairly easy and is detailed in Amazon's documentation
The second one is entirely up to you since it depends on your database solution, but if you're limiting yourself to one or two providers the easiest way is probably to just add the attribute amazonId to the user profile.
The third one will look something like this:
#Controller
public class OidcController {
#Autowired
private ObjectMapper objectMapper;
#RequestMapping("/login/amazon")
public String handleAmazonOidc(#RequestParam String access_token) {
// verify that the access token belongs to us
Content c = Request.Get("https://api.amazon.com/auth/o2/tokeninfo?access_token=" + URLEncoder.encode(access_token, "UTF-8"))
.execute()
.returnContent();
Map<String, Object> m = (Map<String, Object>)objectMapper.readValue(c.toString(), Map.class);
if (!"YOUR-CLIENT-ID".equals(m.get("aud"))) {
// the access token does not belong to us
throw new InvalidTokenException("Invalid token");
}
// Get the user ID from Amazon and get the corresponding user on our end
m = new ObjectMapper().readValue(c.toString(), new TypeReference>(){});
String amazonUserId = m.get("user_id");
User user = getUserFromAmazonId(amazonUserId);
if (user == null) {
// User needs to register first
return "redirect:/register";
}
// Authenticate the user in the current security context
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(user, token, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(token);
// Redirect the user to the front page
return "redirect:/";
}
}
Fourth one is easy, just redirect the user in the callback in the UI:
amazon.Login.authorize(options, 'https://www.example.com/login/amazon');
Now, you're in some trouble since you've already got users in the database that hasn't got an Amazon user ID to look for so you'll probably have to run both authentication schemes in parallel for a while and allow users to connect with Amazon while they're logged in with username and password. Modifying the above controller to insert the Amazon user ID in the current user profile instead of setting it in the security context should be fairly straightforward though.

Turn AuthenticationResult into MVC session

What?
I have an API that takes a username and password and can return an AuthenticationResult. I want to make use of that token in order to start a session within the MVC app. Here's the flow of thins:
User goes to MVC app
User gives password and username
MVC calls API and sends username and password
API returns token to MVC app
After step 4, what can I do to start a session within MVC.
Info on the scenario:
We want to leverage Azure Active Directory to keep all our user info there, but we want users to be able to register using any email, not just our domain. We plan to make an account for every user in AAD using a combination of their email and our domain(since account created in AAD have to belong to a domain). So if the user's email is john#gmail.com, AAD will store johnatgmailcom#ourdomain.onmicrosoft.com
Why?
We can't force a user to create an account using our domain.
We don't want users to see the AAD login screen
We don't want to store any sort of user account info in our DB
We plan to leverage AAD in the future within an iOS/Android apps so having authentication outside the MVC app would allow for this
This is the POC code that we have in our API that authenticates a user login request coming from the MVC app:
AuthenticationContext context = new AuthenticationContext("https://login.microsoftonline.com/cccccccc-cccc-cccc-cccc-ccccccccccccc/oauth2/token");
try
{
UserCredential uc = new UserCredential(userCredendtials.Username, userCredendtials.Password);
AuthenticationResult azureADToken = context.AcquireToken("https://graph.windows.net#" + "ourdomain.onmicrosoft.com", clientID, uc);
return Ok(azureADToken);
}
catch
{
// We didn't authenticate user, send not found - generic error, we can change this
return NotFound();
}
We then check what the result of the API call was within the MVC app to respond accordingly. The $1,000,000 question is how can we start and mange the MVC session as if we were using something like ASP.Net Identity using the token???
We can modify the API and the MVC app as needed but we do have the rewuirement of letting users create their account with any email and to store their info on AAD. If this is totally on the wrong path, any advice is appreciated!
The scenario you described is not supported and not recommended with Azure AD. If you want a white label experience, where uses can pick arbitrary usernames and you can fully customize the cred gathering page, please consider Azure AD B2C: http://blogs.technet.com/b/ad/archive/2015/09/16/azure-ad-b2c-and-b2b-are-now-in-public-preview.aspx

Signin with Micsrosoft Account without requesting consent to access the Contact information

I'm using ASP.Net MVC 5 and would like to allow my users to use Microsoft Accounts for signing.
The default setup to use Microsoft Account will ask permission from the end user to access the contact list in addition to the profile.
Is it possible to have a more limited access? My web application has nothing to do with contacts of the users and therefore I don't want to unnecessarily request this.
OK This is done by using the wl.emails scopes
MicrosoftAccountAuthenticationOptions msao = new MicrosoftAccountAuthenticationOptions();
msao.Scope.Clear();
msao.Scope.Add("wl.emails");
msao.ClientId = "...";
msao.ClientSecret = "...";
app.UseMicrosoftAccountAuthentication(msao);

Using OAuth but store extra information in my own DB

I've been looking into OAuth for a while, but haven't implemented it in any of my applications yet. I'm having trouble really understanding the full concept, so I still have a few questions that I haven't found an answer to, so I hope that anyone can help me.
I want a user to be able to start my application (WP8), login to facebook / twitter / microsoft / ... .
When he gets authenticated, I want to actually save this user to my own DB so I can add some user specific stuff like preferences, posts, ... .
What do I need to save in my own DB to specify a user?
Do I need to save the token itself or is this something that will be invalidated after a while? Or do I need to specify the user's name? With other words: What can I use as a unique identifier?
And what happens when a user would authenticate with for example facebook and he deletes his account?
And one more question, would you ever allow a user to connect to an application with 2 different service providers? If so, how would you make the coupling of these 2 providers to 1 user in your own DB?
I hope my questions are clear enough!
If not, don't hesitate to ask for more information!
Kind regards,
Gert
I assume that you have your own back-end where you authenticate your own users and your WP8 application is just a client.
First, let me distinguish between a user credential and a user profile. User credential is something that validates who the user is, e.g. username/password, facebook user id supplied with a valid auth token. User profile, is what you store in your own database about the user.
You also need to distinguish between a token you use to authenticate the user and the AccessToken Facebook needs to grant you access to user's data.
So... to answer your questions:
What do I need to save in my own DB to specify a user?
Create a record with user data (like preferences, and your unique user ID), and user's login method (e.g. Facebook) and credential (e.g. Facebook's user ID). This is your user's profile.
Do I need to save the token itself or is this something that will be invalidated after a while?
You can also store the Facebook AccessToken here if you've been granted "offline access" privileges by Facebook, but that is used for Facebook's access by you... not by the user's access to your app/back-end. For user's access you could just use a mechanism similar to cookie-based authentication - it's up to you. You could use the AccessToken as a kind of a "cookie", but you would need to always check against Facebook that it's valid.
With other words: What can I use as a unique identifier?
You could treat Facebook's ID as unique (so long as you never allow another account in your user profile DB to link with the same Facebook account)
And what happens when a user would authenticate with for example facebook and he deletes his account?
It's a good idea to have users still create a username/password combination that works with you site and only rely on Facebook login for convenience. In any case, Facebook provides a "Deauthorize Callback URL" when you create an app profile on Facebook. This is called when a user deactivates your app or deletes an account with Facebook. When you receive this call, you could send your user an email when an auth link to setup a different credential so as to not lose access.
would you ever allow a user to connect to an application with 2 different service providers? If so, how would you make the coupling of these 2 providers to 1 user in your own DB?
Sure, you could do that. Say you'd want to allow a Twitter account as well. You'd need to add a Twitter user ID field to your user profile database.
Here's another tip: create an ASP.NET MVC4 project in Visual Studio - the template includes an example of how to set up a user profile database with OAuth login.
Hope it gives you the high-level overview to investigate further.

Resources