ASP.NET Authentication and Provider - asp.net

I am trying to navigate from one website on my localhost to second website on my localhost.
Both sites have their own membership provider. I'm trying to use a FormsAuthorizationTicket from site #1 to SSO a user into site #2.
Currently I'm getting this error:
System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed
Steps I have taken up to this point include:
Setting the element to specific key values
Set the machineKey attributes of validation and encryption to "3DES"
Verified through logging that the encrypted ticket has the same value in the #2 website as it was given in the #1 website.
My code is here:
*FormsAuthentication.Initialize();
FormsAuthenticationTicket newTicket = new
FormsAuthenticationTicket(1 // Ticket Version
, Login1.UserName // User Name
, DateTime.Now // Creation Date
, DateTime.Now.AddDays(1) // Expiration Date
, true // Is Persistant
, Login1.UserName); // This should be a list of Roles
string strEncyptedTicket = FormsAuthentication.Encrypt(newTicket);
HttpCookie myCookie = new HttpCookie("cryptCookie", strEncyptedTicket);
myCookie.Values.Add("username", Login1.UserName);
myCookie.Values.Add("cryptTick", strEncyptedTicket);
Response.Cookies.Add(myCookie);*
In website #2 I created a landing page to verify the ticket and redirect to a members only page. During decryption is when I get the error specified above.
Here is my landing page code on website #2:
*FormsAuthenticationTicket fat2 = FormsAuthentication.Decrypt(Request.Cookies["cryptCookie"].Values["cryptTick"]);
MembershipUser mu = Membership.GetUser(Request.Cookies["cryptCookie"].Values["username"]);
if (mu == null)
{
lblInfo.Text += "member not found";
return;
}
Response.Redirect(#"~\MemberPages\MemberPage.aspx");*
If anyone has an idea to help I'll be happy to try.

Both sites need to share the same machine key.

Ian is correct in that your sites need to have a matching machine key. Also, you need to make sure that your membership providers have the same setting, particularly concerning password encryption.
Also, why are you handling this completely in code? You should be able to configure this functionality withing the Web.Config of both sites very easily. In essence, you are doing a lot of rework and introducing potential problem areas where it is not necessary (unless you have reason that you have not stated here).

Related

ASP Identity : Binding Sessions To Request Url (Sub Domains)

I don't think the title of the question is particularly accurate but that's how best i could title it.
Without summarizing, I have an MVC app hosted on Microsoft Azure. The app was built for multiple institutions (each connecting to a separate database) but the Login Module (Asp Identity) is in a central database (users are identified by their institution code). So during deployment, a sub domain is created (still pointing to the app on azure).
My problem is, the app has no regard for the Request Url, the sessions are maintained across domains. This is a serious problem because i cache User data (by session). So if a user Logs in on "domain1.myapp.com" , then opens another tab , logs into "domain2.myapp.com" , all data cached for the user logged in for "domain1" will be used for the user logged in at "domain2". The app doesn't bother to get data for the user in "domain2" since the key for that data value is already present in the session cache.
Okay, I hope the problem is understood. How do i get past this.
Ideas ? implementation ?
EDIT 1
I insert data into the cache by,
HttpRuntime.Cache.Insert("KEY", "VALUE", null, DateTime.Now.AddMinutes(30),Cache.NoSlidingExpiration);
Your caching strategy needs to change when you cache per user and per domain. The simplest approach is just to add the domain and user name to the cache key, which will keep each cache in a separate per user and per domain bucket. Make sure you put a delimiter between the values to ensure uniqueness of the key.
var domain = HttpContext.Request.Url.DnsSafeHost;
var user = HttpContext.User.Identity.Name;
var key = "__" + domain + "_" + user + "_" + "KEY";
HttpRuntime.Cache.Insert(key, "VALUE", null, DateTime.Now.AddMinutes(30),Cache.NoSlidingExpiration);
Note that if you use HttpContext.Session, it will automatically put different domain information into separate buckets because it is based on a cookie (which by default is domain specific). However, HttpContext.Session comes with its own set of problems.

how can I use a Microsoft Account to authenticate to my website

I have a website where a users identity is needed, I'd really prefer not to make them create yet another username/password combo that they have to remember
are there SDK's for allowing authentication from an Microsoft account?
That's rather easy as a default empty template of an ASP.NET 4.5 website shows how to have OAuth2 authentication with google/facebook/liveid/twitter.
http://www.asp.net/aspnet/overview/aspnet-45/oauth-in-the-default-aspnet-45-templates
Check out the Principal Context class. You can create it using a localhost (Machine) or domain context and use the ValidateCrentials(string username, string password) method to authenticate using Windows credentials.
http://msdn.microsoft.com/en-us/library/bb154889.aspx
Here's how I've used it in my website. (Put this in a POST method of your authentication controller or something)
The code below will take a username say "bob" or "localhost\bob" or "DOMAIN\bob" etc., and get the right PrincipalContext for authenticating the user. NOTE: it's case insensitive here.
public bool ValidateCredentials(string username, System.Security.SecureString password)
{
string domain = Environment.MachineName;
if (username.Contains("\\"))
{
domain = username.Split('\\')[0];
username = username.Split('\\')[1];
}
if (domain.Equals("localhost", StringComparison.CurrentCultureIgnoreCase))
domain = Environment.MachineName;
if (domain.Equals(Environment.MachineName, StringComparison.CurrentCultureIgnoreCase))
using (PrincipalContext context = new PrincipalContext(ContextType.Machine))
{
return context.ValidateCredentials(username, password.ToUnsecureString());
}
else
using(PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
//return context.ValidateCredentials(domain + "\\" + username, password.ToUnsecureString());
return context.ValidateCredentials(username, password.ToUnsecureString());
}
}
Microsoft provides the Live Connect SDK for integration Microsoft services into your applications, including the Microsoft Accounts identity provider.
There is a specific example on Server-Side Scenarios which should cover all you need to get integrated.
Do you mean from an active directory windows account? If so you could use windows authentication and just have the index page sign them in automatically.
http://msdn.microsoft.com/en-us/library/ff647405.aspx
Use the following commands in your code behind file to get the relevant information for signing in:
System.Security.Principal.WindowsIdentity.GetCurrent().Name
User.Identity.IsAuthenticated
User.Identity.AuthenticationType
User.Identity.Name
The amount of changes / rebranding / deprecation / dead links from Microsoft drives me crazy. In any case, the latest version of this from what I've found is "Microsoft Account external login", which can be first set up on the Microsoft Developer Portal.
I found a guide that explains how to do this for .Net Core at https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/microsoft-logins, though the first half (e.g. setting the Redirect URI) isn't framework-specific.
I also found some relevant source code for .Net Core at https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountOptions.cs, which shows some of the Claims (user details) that are retrieved:
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
ClaimActions.MapJsonKey(ClaimTypes.Name, "displayName");
ClaimActions.MapJsonKey(ClaimTypes.GivenName, "givenName");
ClaimActions.MapJsonKey(ClaimTypes.Surname, "surname");
ClaimActions.MapCustomJson(ClaimTypes.Email,
user => user.Value<string>("mail") ?? user.Value<string>("userPrincipalName"));
The support from the latest version of .Net Core suggests to me that this external login API still works. I haven't tested them out yet, I will update if I get to do this login integration.
Simply use "Live Connect" via Oauth 2.0:
http://msdn.microsoft.com/en-us/library/live/hh243647.aspx
or
https://dev.onedrive.com/

ACS - bypassing user redirection to IdP?

I have only recently been looking into ACS, AAL, WAAD and I would like to avoid redirecting users to the login page of their IDP. I want to keep my users within my site and present them with a dropdown to choose who they wish to authenticate with and an area to request a username and password, then acquire token via code. Is this possible?
I have been reviewing some sample applications and produce a quick mock-up, but cant seem to get things working e.g.
_authContext = new AuthenticationContext("https://littledeadbunny.accesscontrol.windows.net");
string enteredEmailDomain = UserNameTextbox.Text.Substring(UserNameTextbox.Text.IndexOf('#') + 1);
IList<IdentityProviderDescriptor> idpdList = _authContext.GetProviders("http://littledeadbunny.com/NonInteractive");
foreach (IdentityProviderDescriptor idpd in idpdList)
{
if (String.Compare(ServiceRealmDropDownList.SelectedValue, idpd.Name, StringComparison.OrdinalIgnoreCase) == 0)
{
Credential credential;
credential = new UsernamePasswordCredential(enteredEmailDomain, UserNameTextbox.Text, PasswordTextbox.Text);
_assertionCredential = _authContext.AcquireToken("http://littledeadbunny.com/NonInteractive", idpd, credential);
return;
}
}
Using the code above, when I try to use the Windows Azure Active Directory User (admin), i get the error "Data at the root level is invalid. Line 1, position 1." where I attempt to acquiretoken.
When I use Google, I get an error "0x8010000C: No identity provider matches the requested protocol".
If there is a working sample? if I am doing something obviously wrong, I would appreciate the correction.
This is not supported for passive identity providers. IdPs like Google, Facebook, etc. don't want other people collecting credentials for them, as this leads to security issues and possible phishing attacks. They also don't support it because they need to be able to show a permission dialog (that screen that asks the user if they want to release data to you) which they can't do without the browser redirecting to them. Furthermore, Google in particular supports two-factor auth, which you couldn't replicate, and generally collecting credentials opens up whole cans of worms around other UI problems such as incorrect or forgotten passwords.
This is also generally a bad user experience, because your users are fairly likely to already be logged in to Google and have cookies there. If so, and if they've already consented to your app, they would just be silently redirected back to you. In your scenario, even if the user is already logged in they'd still have to provide a username/password.
The correct way to do these sorts of logins is to render a browser control in your app that allows the user to log in at their IdP, which is what AAL helps with.
I had the same error, executing a powerscript solved that error
PS C:\windows\system32> $replyUrl = New-MsolServicePrincipalAddresses
-Address https://mydomain.accesscontrol.windows.net/
PS C:\windows\system32> New-MsolServicePrincipal -ServicePrincipalNames
#("https://mydomain.accesscontrol.windows.net/") -DisplayName
"MyDomain Namespace" -Addresses $replyUrl
But i'm stuck anyway with a 403 permission error
If you get any further i would like to know how :)

Check other user's role membership (IsInRole, WindowsIdentity/Principal)

I'm writing ASP.NET code to run on an internal network where Windows Authentication will be used. Certain operations will require me to run a group membership check on other users (not the current user)
NOTE: I am NOT trying to impersonate this account, or access any information in the context of this other user. Just trying to find out what kind of user they are for internal business logic.
My first thought was to use
new WindowsPrincipal(new WindowsIdentity("MACHINENAME\\username"))
.IsInRole("MACHINENAME\\Group1")
However, the WindowsIdentity constructor fails with a SecurityException "The name provided is not a properly formed account name".
If I strip MACHINENAME\ from the parameter, I get a different error: There are currently no logon servers available to service the logon request
The WindowsTokenRoleProvider role provider explicitly only works with the current user, and will not check other user accounts.
Are there security restrictions to checking roles of other users? Would it make a difference if the web server was on a domain and I were checking domain accounts?
In the end, I'll need to have this work on an AD domain, but would prefer a solution that will work on either local or AD accounts.
Thank you
UPDATE: I've been able to test this on a domain now -- the code does work in an AD context so long as I don't use the domain name (test "username" against "Group1", not "DOMAIN\username" against "DOMAIN\Group1")
So how would I get this to work in the context of local users and groups?
Based on Rob A's comment, PrincipalContext and UserPrincipal are the classes I apparently need to use:
using (PrincipalContext ctx = new PrincipalContext(ContextType.Machine))
{
var u = UserPrincipal.FindByIdentity(ctx, IdentityType.Name, "username");
var b = u.IsMemberOf(ctx, IdentityType.Name, "Group1");
var groups = u.GetAuthorizationGroups();
}
And by altering the ContextType, can switch between local accounts and AD accounts. I wish this was built into a RoleProvider, but I guess that's something I'd have to do for myself.

requiresuniqueemail=true implementation in asp.net site

Hi people I got a social networking site that is running live right now.
The first time I launched my site I let requiresuniqueemail=false set-up on my web.config in order for me to create dummy accounts for testing purposes and to start up the site you know. However the site is kind of stable right now with almost 5k members.
I would like to set-up the requiresuniqueemail to true so that users cannot reuse their existing email address and for me to make it sure that there will be unique email ad for each site user. I know the site got like 100 users with the same email address.
What could be the problem I'm going to face if I do this right now(requiresuniqueemail="true") and how to do this efficiently (without errors and if possible sitewide say in the global.asax)?
I tested and I already got an error if I logout an account.Like say a user try to click log-out this code runs:
Dim d As DateTime = DateTime.Now.AddMinutes(-1 * Membership.UserIsOnlineTimeWindow)
Dim theuser As MembershipUser = Membership.GetUser()
theuser.LastActivityDate = d
Membership.UpdateUser(theuser)
If Not Cache(Page.User.Identity.Name.ToLower() + "currentstatusnow") Is Nothing Then
Cache.Remove(Page.User.Identity.Name.ToLower() + "currentstatusnow")
End If
Then an exception occured on updateuser() function saying
System.Configuration.Provider.ProviderException: The E-mail supplied is invalid.
This is just one instance I know that I encountered a problem. Hoping to hear your ideas guys.....

Resources