Although I am currently developing this WinForms application on our Sharepoint server I intend for the finished program to function from any computer on the Domain. I'm using the WSS web services to get all the information I use from Sharepoint.
I have written some code which will check Sharepoint Permission masks, with logical OR against mask, for all the permissions it covers but I am having trouble returning the Sharepoint mask for the current user. I would like users to be able to log right in through Windows Authentication so this was my immediate idea.
NetworkCredential credentails = CredentialCache.DefaultNetworkCredentials;
var userInfo = userGroupService.GetUserInfo(credentails.UserName);
However although I am able to return the permission collection for the entire Sharepoint site with DefaultNetworkCredentials (as in bellow snippet) the properties are empty strings, so I can't use it to get the UserName.
permissionService.Credentials = CredentialCache.DefaultNetworkCredentials;
permissionService.Url = "http://localhost/mySite/_vti_bin/Permissions.asmx";
// Web service request works
XmlNode node = permissionService.GetPermissionCollection(siteName, "Web");
// But I need to identify current user from this collection somehow still
I read that Windows Authentication suffers from a double-hop issue, which I want to avoid, but as I am developing on the server Sharepoint & IIS are running, I can't see this causing an immediate issue.
Is there a way around this or a better way to get the current users permission mask?
If the current user for wss will always be the same as the user currently logged on to the pc
var userInfo = userGroupService.GetUserInfo(Environment.UserDomainName +#"\"+ Environment.UserName);
or to get the permissions for the currently logged on user
XmlNode currentUserPermission = userGroupService.GetRolesAndPermissionsForCurrentUser();
You are dealing with an issue where the authentication cannot move beyond one remote host; this is known as the "one-hop" limitation.
To overcome this, you have to get into "Constrained Delegation," where a computer/account are expressly authorized to receive and accept authentication credentials from another computer/account. This is set up in Active Directory by defining the appropriate Service Principal Names (SPN's) on either "end" of the delegation.
You can get more details about Constrained Delegation here.
Good luck! CD can be a bit of a pain to set up, so tread carefully.
Related
My scenario:
A client app (Net Core WPF) should somehow find out the current user's identity (for example using System.Security.Principal.WindowsIdentity.GetCurrent()) and authenticate with a REST server application (Net Core) which has access to AD (it knows the address, name and password of root AD DirectoryEntry). The authentication should be successful if and only if the user from the client app is found among users in AD. This is an intranet setup btw.
Solutions to similar questions here on SO (for example How to get the current user's Active Directory details in C#) generally propose using DirectorySearcher and filtering on user name "(sAMAccountName=theUserIWantToMatch)".
But IMHO this is not sufficient:
1) It is not secure enough, you can easily impersonate anybody just by creating a user with a similar name. Not to mention man-in-the-middle attacks.
2) It needn't even be malicious, plenty of people have similar names. I might have connected to the intranet network via VPN using a computer with a similar user name (similar to somebody else already on that network).
Can you think of a better way to match the users (using some GUID or token for example) or completely different authentication method? Just to reiterate: I can't use usual ASP.NET windows auth because my client is a WPF app that communicates with the server using HttpClient instance.
Thank you.
A fail-proof way of getting the exact user that's logged in is by using the SID, which is available from WindowsIdentity.GetCurrent().User.
From there, you can bind directly to the AD object using the LDAP SID binding syntax of LDAP://<SID=XXXXX>.
That will look something like this:
var sid = WindowsIdentity.GetCurrent().User;
var currentUser = new DirectoryEntry($"LDAP://<SID={sid}>");
If the computer you're running this from is not joined to the same domain as the user (or trusted domain), then you will need to include the domain name in the LDAP path:
var currentUser = new DirectoryEntry($"LDAP://example.com/<SID={sid}>");
This method is also faster than any other method, since you're not performing a search and then binding to the object. It's all done in one network request.
I am just starting out with the c# Google.Apis.Gmail.V1 classes and using a service account to read a mailbox.
My code works fine when I use the following snippet
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(ServiceAccountEmailAddress)
{
User = "abc#test.domain.com",
Scopes = new[] { "https://www.googleapis.com/auth/gmail.readonly" }
}.FromCertificate(certificate));
With that code I can call the following successfully
if (credential.RequestAccessTokenAsync(CancellationToken.None).Result)
{
}
But I need to modify the email messages so I changed the scope from
https://www.googleapis.com/auth/gmail.readonly
to
https://www.googleapis.com/auth/gmail.modify
I now get an exception when requesting the access token
{"Error:\"unauthorized_client\", Description:\"Unauthorized client or scope in request.\", Uri:\"\""}
I have checked the service account (*.iam.gserviceaccount.com) in the Google Developers Console and I have tried all options for permissions including OWNER which should give me Full access to all resources but no joy.
I think I am just missing a simple step but I am unsure of where to look next.
TL;DR
I would read through this, but here is the short version. I know this is an older post, but hopefully it finds you!
If you have not updated/white-listed the service account's privileges/scopes in the Google Admin Console you will need to do that, make sure the domain has API access enabled, make sure the service account is setup properly, when creating the "certificate" object be aware its parameters so that it is being instantiated correctly, check the permissions on the account being impersonated and finally make sure you've made an appropriate Google Apps service account key (could have easily made an inappropriate key type.)
White-listing Google APIs in the Admin Console
This gives the Google Apps service account the abilityto use whatever scopes you provide in your Google Apps domain.
Login to the Google Apps Admin Console by using the following link.
https://admin.google.com/
The Google Apps user account must have sufficient privileges to modify domain related settings. It does not have to be the account used to create the Google Apps project in the developer console. If the account does not have privilege you will be directed to a completely different screen with no options to click on varying domain controlling web apps like "Security", "Roles", "Support", "Groups" and etc. Instead you'll dumped onto a page that shows things like "Gmail", "Drive", "Docs" and etc. that is typical user apps. The current link it drops you at is https://apps.google.com/user/hub
Click “Security.”
Click “Show more” option at the bottom of the security options list.
Click “Advanced Settings” to get the more options.
Select the “Manage API client access” link.
Now certain API scopes must be white-listed for the desired service account. In the “Client Name” text box provide the service account’s client ID. The client ID is obtained in the developer console. In the “One or more API scopes” add the desired scopes; comma delimited.
Note, if there are existing scopes they will be removed so be sure to re-add any that will be needed.
Enable Domain Wide API Access
Login to the Google Apps Admin Console by using the following link.
https://admin.google.com/
Go to the “Security” page.
Under “API reference” section
Make sure that “Enable API access” is enabled.
Creating an Appropriate Google Apps Service Account Key (Probably this)
Go to the Google Developer Console. Login as the Google Apps user that created the Google Apps project/service account. https://console.developers.google.com/
Navigate to the particular project with which you created the service account.
Click the "Service Account" button on the left of the project's page to bring up a page with all of the project's service accounts.
Click the vertical ellipse widget all the way to the right of the desired service account's row. Select “Create Key.”
Select .p12 key as it looks like this is what you're trying to use. Click "Create." Be sure to protect this key.
I have found that if the key is not created this way then it leaves open the possiblity for making either an API key or an OAuth 2.0 client/user key. These are the wrong types of keys to use in this case you would need to have created a service account key. The way outlined above forces you to create a service account key.
Modifying the Existing Google Apps Service Account's Settings
I'm not going over how to setup the actual service account, one thing you may need in your case is to make sure that the service account has domain wide delegation enabled. This is toggled in the Google Developer Console. Should be pretty easy to find.
Code
You do not provide your entire code base for creating the token, so just want to add a few things you might be doing improperly.
Make sure when you create the certificate that the secret you provide is the default "notasecret" string. This secret is currently the default value provided by all keys distributed by Google and is immutable during key creation. I had a link to prove this, but have since lost it.
X509Certificate2 certificate = new X509Certificate2(certificateFilePath, "notasecret", X509KeyStorageFlags.Exportable);
Just trying to advocate proper coding. While I have found some bugs in the past with Google's constant values that required additional string manipulation (adding additional slashes.) You should really be using the string constants that they provide in place of literals. I only say to use these because it provides a layer of abstraction, who is to say Google will never change the literal; unlikely.
In your case the new scope is:
GmailService.Scope.GmailModify
While the old scope was:
GmailService.Scope.GmailReadonly
Otherwise, everything code wise looks good to me.
Another thing to try would be to make sure that the actual Google Apps user account being impersonated by the service account has sufficient privileges. I would suspect a different error if this were the case, would be getting a 403 in the response instead. Anyway, in your case this is the "abc#test.domain.com" account. Once again you would go to the Google Admin Console, check its roles make sure it has sufficient roles checked for whatever it is you're trying to do. I don't know what specifically you'll need in this case, best bet would be to give it the same permissions as the "Super Admin" role then remove permissions as you go to see what it might actually need. Otherwise, if possible just give it "Super Admin."
If I was a gambler I would put my money on an inappropriately created service account key. I just recently ran into this and it was the only thing that produced the same exact error you're receiving. Other things would get me the same "Description" value in the response token, but not the same "Error" value. I'm not really even sure how the culprit key was made, because I didn't make it. I just know the fix was to recreate a new key with the steps above and that fixed the issue.
I have a simple wpf client (few text boxes) that uploads some data to a web service. And I want to use windows authentication to go with my application.
I am checking in OnStartup of App.xaml, whether or not the user is authenticated. My question is around what is the meaning of Thread.CurrentPrincipal.Identity.IsAuthenticated.
I don't want my application to be used from outside my network as it is connecting to a web service and uploads data. But my assumption is as long as you run this application from inside any windows network the above mentioned property will always return true?
So how do I find out if the application is being run from inside my network. I don't think checking domain name or role name is any different, because I can always setup a domain and name it whatever I want. I don't want to prompt user for username or password of any sort.
How do you check Identity of user against a particular AD (AD might not be publically available). Basically the application should only works from my local network or through VPN.
var context = new PrincipalContext(ContextType.Domain, "DOMAINNAME");
var result = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName);
If the result is null, then the user does not exists in the AD domain.
You can also user DirectorySearcher class to query AD based on a filter criteria. This is more useful only if you would like to retrieve additional details about the user like contact, email address etc.
I thought its simple to get the logged in username, in fact, it works fine with most of the responses available on stack overflow but when I publish the website all method fails.
Can anybody please guide me to get the name of the logged in user from Windows with following condition.
I just need logged in user name so forget about AD when you write the response.
I cannot change to Windows authentication mode because user may be a guest user who is not part of company but still have access to my intranet website
it’s not possible to change the user browser setting as there are more than 6000 users
I cannot disable the anonymous authentication as I want everyone to be able to use the website
I have already tried following solution and all works fine when I run the website on debug mode but all fails to return the username when I publish the website on IIS so please help me with some new as solution
string _windowLogonUserName = System.Environment.UserName.ToString()
string _windowLogonUserName =
WindowsIdentity.GetCurrent().Name.Remove(0, _adDomainName.Length + 1)
string _windowLogonUserName =
System.Web.HttpContext.Current.User.Identity.Name.ToString();
System.Security.Principal.WindowsIdentity.GetCurrent().Name;
AppDomain appDomain = Thread.GetDomain();
appDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal windowsPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal;
Logger.Write("username principal" + windowsPrincipal.Identity.Name);
Request.ServerVariables["LOGON_USER"]
It sounds like you're publishing the site outside of the AD domain. if the server is not on the domain, it won't be able to authenticate (or even accept) Windows users. The basic answer is that you can't get it.
If the server is internal (on the domain) then you can enabled integrated windows auth in IIS. Here's a reference.
i have a web service hosted on another server with the Anonymous Access CheckBox in IIS is already checked. when my local web application is trying to access the web service, i still get the "The request failed with HTTP status 401: Access Denied." error. my web application is calling the web
service like the following:
MyObject.WebService ws = new MyObject.WebService ();
ws.Retrieve(someParams);
what am i missing here?
Here is a good reference on diagnosing 401 errors.
From that, one place to start is looking at the credentials you configure for the anonymous user. If they are incorrect (if perhaps the user password was changed elsewhere) you will get an HTTP 401.
Make sure your directory permissions are also set to allow everyone read access. A lot of times doing local dev work I will forgot that the directory being accessed has a seperate set of permissions that need to be altered.
Cheers!
Check this http://www.c-sharpcorner.com/UploadFile/mahesh/40107282006095201AM/401.aspx.
//Assigning DefaultCredentials to the Credentials property
//of the Web service client proxy (myProxy).
myProxy.Credentials= System.Net.CredentialCache.DefaultCredentials;
This code worked for me.
have you try un selecting the allow iis to control password some times that get out of sink.
try the site and it may work. you sould be able to reenable control after that
Try the following (note the PreAuthenticate thingy):
MyObject.WebService ws = new MyObject.WebService();
ws.PreAuthenticate = true;
response = ws.Retrieve(someParams);
For more detailed explanation why this may work you can reference following answer here http://social.msdn.microsoft.com/Forums/en-US/asmxandxml/thread/3ae9753d-2d97-45b9-9ba2-6d551fe60a48/.
I think what might be happening is that you are getting a 401 - permission denied but as to whom the permission is denied to is unclear. I am guessing at this point you have checked the NTFS permissions on the machine, and have confirmed that you do have access.
Next I would look at what account the application pool uses. If it is the default setup, it will probably be the NT Network Service Account. If that is the case, confirm that the account does have access to the application directory. If that is also the case it might perhaps be a COM+ security setting. By default your network service account does not have permission to remotely launch components. If this is the case you will be seeing errors in the system and security log that will say things link, "Unable to launch component "
Looking at the IIS log files and the system and security event logs on the iis server often yield more clues.
Hope it helps
Best Regards
Rihan Meij