Livelink WCF Webservice - Auth Issues - asp.net

I'm a Sharepoint/MS Developer and not too familiar with Livelink. Anyways, I see they have a .NET WCF Service. I'm attempting to do Authentication using this web service and as far as I can read from the API docs, It shouldn't be too difficult.
According to the docs, I need to auth initially with a Admin user which I do and this works fine. Then I can impersonate using the currently logged on user.
Everything works fine until I get to the ImpersonateUser part which fails with a very generic "Insufficient permissions to perform this action." error. Is this a issue on the client side? or LL side? Possible Kerberos not setup propely or at all?
Herwith the code:
private string ImpersonateUser(string adminToken)
{
string userToken = string.Empty;
llAuthentication.OTAuthentication fLLAuthentication = new llAuthentication.OTAuthentication();
fLLAuthentication.AuthenticationToken = adminToken;
fAuthServiceUser = new AuthenticationClient();
fAuthServiceUser.Endpoint.Address = new EndpointAddress(this.ServiceRoot + "Authentication.svc");
fAuthServiceUser.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
userToken = fAuthServiceUser.ImpersonateUser(fLLAuthentication, WindowsIdentity.GetCurrent().Name.ToString());
return userToken;
}

This has nothing to do with Windows authentication. It just means the livelink user you're initially using to login with does not have the right to impersonate other livelink users. Ask your livelink admin to grant this right (I dno't know the exact right off-hand, sorry)

Related

ADFS 2016 On behalf of flow : cannot get any user informations

I'm trying to implement the "on behalf of" flow in an application using ADFS 2016 as STS. As a reference, I look at this Microsoft tutorial (https://learn.microsoft.com/en-ca/windows-server/identity/ad-fs/development/ad-fs-on-behalf-of-authentication-in-windows-server). It's working as it should, I can login into my web application and then use my original access token in UserAssertion to generate a new access token with the proper audience to call my API BUT I found absolutely no way to include any user informations (sub, name, email, upn etc.) into the access token for my API, even if I set claim rules into my ADFS configurations for the API.
I checked the communication between my app and adfs using Fiddler and everything looks like the informations in the tutorial. See the screen shot of the "on behalf of" request below :
Here's the resulting access token :
Finally, here's the code I use to generate my new access token :
private async Task<string> GetAccessToken(ClaimsPrincipal user, string originalAccessToken)
{
var authority = "[authority]";
var context = new AuthenticationContext(authority, false);
string userName = user.FindFirstValue("upn");
var userAssertion = new UserAssertion(originalAccessToken, "urn:ietf:params:oauth:grant-type:jwt-bearer",userName);
var cc = new ClientCredential("https://localhost:44387/", "[client_secret]");
var result = await context.AcquireTokenAsync("https://localhost:44339/", cc, userAssertion);
return result.AccessToken;
}
Have you struggle with that scenario and if yes, did you find a way to fix this ?
Thanks
I've only used the Microsoft On Behalf Of flow with Azure AD and not ADFS, but it looks like you need to send a more detailed scope in your User Info request.
Maybe try sending 'openid profile email', to indicate that you want that type of detail, as in Section 17 of my blog post. Of course this assumes that this type of data has been registered for all users.
TROUBLESHOOTING
Looks like one of these will be the cause:
A suboptimal Microsoft library that does not allow you to send the required scope
Or ADFS 2016 perhaps lacks the scope features that work correctly in Azure AD
I would concentrate on making extra sure you are sending the correct form URL encoded request message, using a tool such as curl, Postman or a plain C# HttpClient. Here is the code I used to send the correct scope - using an open source library rather than a Microsoft one:
Sample NodeJS Code
If you can get the scope sent correctly then you should have a resolution either way:
Either you get the correct data and can update your code
Or the behaviour you want is not supported by ADFS
Good luck ...

The remote server returned an error: (401) Unauthorized. Using CSOM in ASP.NET

I'm tried to pull some SharePoint 2013 list data I created which works fine when running locally on my machine and when run locally one the server. I'm user the same credentials when running both locally and locally on the server. The issue is when I publish and navigate to my ASP.NET app on the server I get the "The remote server returned an error: (401) Unauthorized." Error...
I've looked at a bunch of the posts on stackoverflow and some other articles on the web
This points out that the context seems to be using IUSR:
http://blogs.msdn.com/b/sridhara/archive/2014/02/06/sharepoint-2013-csom-call-from-web-part-fails-with-401-for-all-users.aspx
This one mentions to try setting the default network credentials:
https://sharepoint.stackexchange.com/questions/10364/http-401-unauthorized-using-the-managed-client-object-model
I've tried using the fixes mentioned in the article as well as trying to force the context to use DefaultNetworkCredentials but no luck. I would like for the app to use the credentials of the logged in user and not the machine...
Here is the code I'm using:
SP.ClientContext context = new SP.ClientContext("MySPDevInstance");
context.Credentials = CredentialCache.DefaultNetworkCredentials;
Entity entity = context.Web.GetEntity(collectionNamespace, collectionName);
LobSystem lobSystem = entity.GetLobSystem();
LobSystemInstanceCollection lobSystemInstanceCollection = lobSystem.GetLobSystemInstances();
context.Load(lobSystemInstanceCollection);
context.ExecuteQuery();
LobSystemInstance lobSystemInstance = lobSystemInstanceCollection[0];
FilterCollection filterCollection = entity.GetFilters(filter);
filterCollection.SetFilterValue("LimitFilter", 0, 1000);
EntityInstanceCollection items = entity.FindFiltered(filterCollection, filter, lobSystemInstance);
The server is running IIS 6.0
Any advice would be much appreciated!
Thank you
I presume your ASP.NET web site is using Windows Integrated (NTLM) authentication. A user authenticated this way cannot authenticate to a second location from the server side (the web server.) You are experiencing what is known as the "double-hop" (1) limitation of NTLM. You must use a dedicated account on the server side, or if you really do want to use the logged-in user's identity, you must use an authentication scheme that permits delegation, such as Kerberos.
If you really need the user's identity to access SharePoint data and you cannot change the authentication scheme, then the best way to do this is to use the JavaScript CSOM. This means the user is authenticating directly to the SharePoint server (a single hop, not double) and your ASP.NET site serves the page containing this script to the user.
(1) http://blogs.msdn.com/b/knowledgecast/archive/2007/01/31/the-double-hop-problem.aspx
Use Default Credentials worked for me:
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.UseDefaultCredentials = true;
Setup the crendentials by code:
SP.ClientContext context = new SP.ClientContext("MySPDevInstance");
context.Credentials = new NetworkCredential("username", "password");
You should put this at the configuration file to change it without publishing or recompiling the application.
Just to add one more setting that I encountered. If the account is restricted to access only certain servers than add the client machine to that account as well. For example if a web application is hosted on Server A and trying to connect to SharePoint 2010 on Server B with account ABC then make sure that account has access to Server A in Active Directory. Normally the AD account doesn't have restrictions to connect to machines but in my case the account was restricted to only certain machines. I added my web application hosted server to the account and it worked.

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/

Novell eDirectory with .NET DirectoryServices

In our company, we have a project which should use Novell eDirectory with .net applications.
I have tried Novell Api (http://www.novell.com/coolsolutions/feature/11204.html) to connect between .NET applications. It is working fine.
But, as per requirement, we specifically need .net API to connect not with Novell Api, which is not working. Connection and binding with .NET Api DirectoryServices not working.
Our Novell eDirectory is installed with following credentials:
IP address: 10.0.x.xx(witsxxx.companyname.com)
Tree : SXXXX
New Tree Context: WIxxxK01-NDS.OU=STATE.O=ORG
ADMIN Context is: ou=STATE,o=ORG
admin : admin
password: admin
I used Novell Api and used following code
String ldapHost ="10.0.x.xx";
String loginDN = "cn=admin,cn=WIxxxK01-NDS,OU=STATE,o=ORG";
String password = string.Empty;
String searchBase = "o=ORG";
String searchFilter = "(objectclass=*)";
Novell.Directory.Ldap.LdapConnection lc = new Novell.Directory.Ldap.LdapConnection();
try
{
// connect to the server
lc.Connect(ldapHost, LdapPort);
// bind to the server
lc.Bind(LdapVersion, loginDN, password);
}
This is binding correctly and searching can be done.
Now my issue is with when I trying to use .NET APi and to use System.DirectoryServices
or System.DirectoryServices.Protocols, it is not connecting or binding.
I can't even test the following DirectoryEntry.Exists method. It is going to exception.
string myADSPath = "LDAP://10.0.x.xx:636/OU=STATE,O=ORG";
// Determine whether the given path is correct for the DirectoryEntry.
if (DirectoryEntry.Exists(myADSPath))
{
Console.WriteLine("The path {0} is valid",myADSPath);
}
else
{
Console.WriteLine("The path {0} is invalid",myADSPath);
}
It is saying Server is not operational or Local error occurred etc. I don't know what is happening with directory path.
I tried
DirectoryEntry de = new DirectoryEntry("LDAP://10.0.x.xx:636/O=ORG,DC=witsxxx,DC=companyname,DC=com", "cn=admin,cn=WIxxxK01-NDS,o=ORG", "admin");
DirectorySearcher ds = new DirectorySearcher(de, "&(objectClass=user)");
var test = ds.FindAll();
All are going to exceptions.
Could you please help me to solve this? How should be the userDN for DirectoryEntry?
I used System.DirectoryServices.Protocols.LdapConnection too with LdapDirectoryIdentifier and System.Net.NetworkCredential but no result. Only same exceptions.
I appreciate your valuable time and help.
Thanks,
Binu
To diagnose your LDAP connection error, get access to the eDirectory server from the admins, and use iMonitor (serverIP:8028/nds and select Dstrace), in Dstrace clear all tabs and enable LDAP tracing, then do your bind see what happens on the LDAP side to see if there is a more descriptive error there. Or if you even get far enough to bind and make a connection.

How to pass HostingEnvironment.Impersonate credentials to ExchangeService EWS?

Is it possible to pass the credentials of the user browsing my asp.net web application to the EWS FindAppointments call?
I'm only trying to return calendar details for the active browsing user, who will without doubt have permission to read their own calendar, so the issue should not relate to Exchange impersonation with the EWS api discussed here.
The code below works just fine when running localhost, but running from the web server, despite Windows Authentication and Identity Impersonation being configured it throws an access denied error.
using (HostingEnvironment.Impersonate())
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.UseDefaultCredentials = true;
service.AutodiscoverUrl(UserEmailAddress);
Mailbox mb = new Mailbox(UserEmailAddress);
FolderId cfCalendarFolderID = new FolderId(WellKnownFolderName.Calendar, mb);
CalendarView cvCalendarView = new CalendarView(DateTime.Now, DateTime.Now.AddDays(30), 1000);
cvCalendarView.MaxItemsReturned = 3;
Perhaps I'm missing a simple way to pass the HostingEnvironment credentials to my ExchangeService object?
Is there a way to check what the service.UseDefaultCredentials are?
I'm not able to use the following as there isn't a way to get the password from the windows authenticated impersonated user.
service.Credentials = new System.Net.NetworkCredential(username, password, domain);
I've also tried the following, but get the same ServiceResponseException access denied errot.
service.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
service.PreAuthenticate = true;
Thanks in advance of your kind assistance.
Additional info which may or may not be relevant:
The Application Pool Identity for the website is NetworkService.
The UserEmailAddress variable is set from an AD lookup based on System.Security.Principal.WindowsIdentity.GetCurrent().Name
EDIT (14th Aug 2012)
To achieve what I'd like to do above, I believe the HostingEnvironment.Impersonate isn't required.
Instead I need to use the ExchangeService's ImpersonatedUserId property.
More details on that here
Only problem though is we're running Exchange 2007 and the power shell command for enabling a service account to impersonate all users (that you would use pass in to the .Credentials parameter) only appears to be compatible with Exchange 2010.
You should try using WebCredentials instead of NetworkCredential - see related SO post. There seems to be an issue with EWS and AutoDiscover + NetworkCredentials

Resources