ASP.NET authentication: adding similar part (domain) to all usernames - asp.net

I am working on an authentication process for an ASP.NET web app. All my usernames follow the same template: login#domain.com. Domain is always the same.
My question is: Is there a way to add the part #domain.com automatically, so users could just type in their login in the username field?
Please, let me know if I need to provide some additional info to find the answer to this question.

Add domain name programmatically if it's not specified by users:
//var userNameWithDomain = "abc#domain.com" or "abc"; //get it from user's
//input
string[] arrUserName = userNameWithDomain.Split("#".ToCharArray());
string userName = null;
string domainName = null;
if (arrUserName.Length > 1)
{
userName = arrUserName[0];
domainName = arrUserName[1];
}
else
{
userName = userNameWithDomain;
domainName = "domain.com";
}

Related

Getting the full user name from User.Identity in Razor.Pages project when authenticating using Azure AD

I am developing my Razor.Pages web application in .Net Core 3.1 and I configured the authentication using my company AD. I can use without any problem the User.Identity.Name to get the user#domain value but I need to get the full name of the person that is logged in so that I can filter some results of a query to an SQL DB based on the user's full name.
I tried googling around but didn't find anything a solution to my problem. Thanks!
After doing some digging around I finally managed to create a method that receives the User.Identity.Name of the logged in user and returns the full name.
Bellow is a snippet of the method!
public static string GetFullName(string domainName)
{
string fullName = "";
UserPrincipal principal;
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
principal = UserPrincipal.FindByIdentity(ctx, domainName);
}
if (principal != null)
fullName = $"{principal.GivenName} {principal.Surname}";
else
fullName = domainName;
return fullName;
}

Asp.net Identity Email Verifcation Token Not Recognized

We are using Microsoft's Identity Framework v2.0 in a web forms application. All is working well. We decided we want to add email verification as part of the new account set up process. If we validate the token after it is created in the same page, we are successful. But if we try to validate the token in a different page, it fails. The process is very simple:
Admin creates a new account by providing user's email and name. (we do not support self registration).
User clicks link he gets in email to validate the email was received.
Here is the code to create the email verification token:
var manager = new UserManager();
var user = new ApplicationUser() { UserName = EmailAddress.Text, Email = EmailAddress.Text, FirstName = FirstName.Text, LastName = LastName.Text };
IdentityResult result = manager.Create(user);
var provider = new DpapiDataProtectionProvider();
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(provider.Create("EmailConfirmation"))
{
TokenLifespan = TimeSpan.FromHours(24)
};
var strToken = manager.GenerateEmailConfirmationToken(user.Id);
//IdentityResult validToken = manager.ConfirmEmail(user.Id, strToken);
strToken = HttpUtility.UrlEncode(strToken.ToString());
NOTE: If we uncomment the line beginning //IdentityResult validToken..., then it succeeds.
Here is the code on the VerifyEmail page:
string userid = Request.QueryString["id"].ToString();
string tokenReceived = Request.QueryString["token"].ToString();
//tokenReceived = HttpUtility.UrlDecode(tokenReceived);
ApplicationUser User = new ApplicationUser();
var manager = new UserManager();
User = manager.FindById(userid);
var provider = new DpapiDataProtectionProvider();
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(provider.Create("EmailConfirmation"))
{
TokenLifespan = TimeSpan.FromHours(24)
};
IdentityResult validToken = manager.ConfirmEmail(User.Id, tokenReceived);
The validToken line does not succeed in this file. I have validated that the strings User.Id and tokenReceived match EXACTLY in both file, so there is no URL corruption going on. (That is why I commented out the UrlDecode since it seems to be decoded by the browser automatically - when I try to decode, it is not 100% the same as the string before encoding).
So I am certain we are calling the same method (ConfirmEmail) and that the two parameters that are passed are exactly the same strings. I am also aware that a token can only be validated once, so I am not trying to re-use them after once validating them.
Any ideas would be welcome.
I think the problem in DpapiDataProtectionProvider - If you use the same instance of this class in creating and validating the token, it'll work fine.
Any reason you are not getting UserManager from Owin Context as per VC2013 template?

how to skip facebook app permissions dialog

Here, I am trying to authenticate user via login and after that I want to skip permissions dialog. But I am unable to achieve this, as it always asking for permissions for app to the user. My intention is if user is not logged into the facebook he/she should be prompted for facebook login and then I will fetch public information by using method Get("/me"). Let me know what I am doing wrong here.
public string GetFBAccessToken(string strAppID, string strAppSecret, string strUrl)
{
// Declaring facebook client type
var vFB = new FacebookClient();
string strAccessTok = string.Empty;
try
{
if (!string.IsNullOrEmpty(strAppID) && !string.IsNullOrEmpty(strAppSecret) && !string.IsNullOrEmpty(strUrl))
{
// Getting login url for facebook
var loginUrl = vFB.GetLoginUrl(new
{
client_id = strAppID,
client_secret = strAppSecret,
redirect_uri = strUrl,
response_type = "code",
state = "returnUrl",
//scope = "",
display = "popup"
});
// Redirecting the page to login url
if (HttpContext.Current.Request.QueryString["code"] == null)
{
HttpContext.Current.Response.Redirect(loginUrl.AbsoluteUri);
}
// Fetching the access token from query string
if (HttpContext.Current.Request.QueryString["code"] != null)
{
dynamic result = vFB.Post("oauth/access_token", new
{
client_id = strAppID,
client_secret = strAppSecret,
redirect_uri = strUrl,
code = HttpContext.Current.Request.QueryString["code"]
});
// Getting access token and storing in a variable
strAccessTok = result.access_token;
}
}
return strAccessTok;
}
catch (Exception ex)
{
//if (HttpContext.Current.Request.QueryString["response_type"] == "code")
//{
// var fb = new FacebookClient();
// var details = fb.Get("/me");
//}
return strAccessTok;
}
}
Regardless to the platform/ language you are using; solution can be as follows.
check use's logged in status. https://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus/
based on Response status, forcefully call your action (i.e. Log in, Get Permission or any additional action if user is already connected). For Log in check this reference document from FB. https://developers.facebook.com/docs/facebook-login/login-flow-for-web/
No. You cannot skip the Login Dialog.
In fact, it is really important for an APP owner to build a trust relationship with your users. I would recommend you to follow the Login Best Practices while authenticating the users using your APP.

asp.net razor allow edit page only for logged in user

I have this profile edit page, but if the user changes id in the url he can change other users profile, how do i deny access to other id's in url
if (!IsPost)
{
//if(!Request.QueryString["ID"].IsEmpty()){
if (!Request.QueryString["UserId"].IsEmpty() && Request.QueryString["UserId"].IsInt())
{
UserId = Request.QueryString["UserId"];
var db = Database.Open("mystring");
var dbCommand = "SELECT * FROM UserProfile WHERE UserId = #0";
var row = db.QuerySingle(dbCommand, UserId);
if (row != null)
{
Email = row.Email;
fullname = row.fullname;
location = row.location;
}
else
{
ModelState.AddFormError("No Profile was selected.");
}
By not allowing to pass the userid as query string parameter but read it from the encrypted Forms Authentication cookie.
So:
var UserId = Request.QueryString["UserId"];
should become:
string username = User.Identity.Name;
This will give you the currently authenticated username and then change only his profile.
There are many ways to do it.
Do not pass User Id as Query String. Pass it in model object
If you decided to pass user id from query string and if you have authentication set in place then you could match the user id passed in query string with user id of logged in user. If these two match, then only allow edit

System.DirectoryServices - The server is not operational

I get an error by a website, on which I use Windows Authentication.
Strange things:
Only occurs if user is not yet saved into database (new unknown user)
Appears only on live system, everything fine on local development environment
This is what I get in a logging mail:
Source : System.DirectoryServices
Message: The server is not operational.
Trace:
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
at System.DirectoryServices.DirectorySearcher.FindOne()
at Smarthouse.Labs.DataAccess.UserListManager.SaveUser(String windowsUserName)
This is how I implement DirectorySearch:
private void SaveUser(string windowsUserName)
{
string[] domainAndUser = windowsUserName.Split('\\');
string domain = domainAndUser[0];
string username = domainAndUser[1];
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain);
DirectorySearcher search = new DirectorySearcher(entry);
try
{
// Bind to the native AdsObject to force authentication.
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
search.PropertiesToLoad.Add("sn");
search.PropertiesToLoad.Add("givenName");
search.PropertiesToLoad.Add("mail");
SearchResult result = search.FindOne();
if (result == null)
{
throw new Exception("No results found in Windows authentication.");
}
User userToSave = new User();
userToSave.FirstName = (String) result.Properties["givenName"][0];
userToSave.LastName = (String) result.Properties["sn"][0];
userToSave.Email = (String) result.Properties["mail"][0];
userToSave.Username = windowsUserName;
userToSave.Guid = Guid.NewGuid();
SaveUser(userToSave);
}
catch (Exception ex)
{
throw new Exception("Error authenticating user. " + ex.Message, ex);
}
finally
{
//Dispose service and search to prevent leek in memory
entry.Dispose();
search.Dispose();
}
}
If more code examples are needed just tell me.
Your problem is that you're using a "plain" domain name to bind - this won't work in LDAP. Actually, if you try to bind to LDAP://MyDomain, what you're really doing is trying to bind to the server called MyDomain.
You need a valid LDAP bind string - something like LDAP://dc=yourdomain,dc=local or something.
To find out what your default LDAP binding context is, use this code snippet:
DirectoryEntry deRoot = new DirectoryEntry("LDAP://RootDSE");
if (deRoot != null)
{
string defaultNamingContext = deRoot.Properties["defaultNamingContext"].Value.ToString();
}
Once you have that string - use that as your bind string to your LDAP server.
And if you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context -- no domain name needed, uses default domain
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
if(user != null)
{
// do something here....
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
You can use bind strings in the format LDAP://mydomain.com:389. I kept getting "Access is Denied" when trying to use the format LDAP://DC=mydomain,DC=com. Once I switched to the LDAP://mydomain.com:389 format, and bound using the AuthenticationTypes.ServerBind flag when constructing my DirectoryEntry, it worked great. This was in Azure App Service.
To add to marc_s's answer above, I needed to search multiple domains.
So for each Domain I did the following:
DirectoryEntry deRoot = new DirectoryEntry("LDAP://" +"DomainName"+ "/RootDSE");
string defaultNamingContext = "LDAP://" + deRoot.Properties["defaultNamingContext"].Value.ToString();
DirectoryEntry mySearchRoot = new DirectoryEntry(defaultNamingContext);
DirectorySearcher myDirectorySearcher = new DirectorySearcher(mySearchRoot);
Similar Error Happened to me (though it happened all the time and not in specific cases like pointed out here) because of a wrong Active Directory connection string. i used the corp instead the prod one .
Use something that works for another app in your organization if exists.

Resources