I'm developing an auto-hosted asp.net app for Sharepoint 2013. I have to use the SPAppWebUrl token value for my requests. So I tried this :
AppManifest.xml : <StartPage>~remoteAppUrl/Pages/Index.aspx?{StandardTokens}</StartPage>
javascript :
var appweburl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));
C# code-behind : Application["SPAppWebUrl"] = Request.QueryString["SPAppWebUrl"];
Nothing worked. Sharepoint sends values for SPHostUrl, SPLanguage, SPClientTag and SPProductNumber only. I read topics about tokens and noted this :
If there is no app web, the portion &SPAppWebUrl={AppWebUrl} is not present.
But I dont understand how I could not have an app web...
If anybody can help please. Thanks.
I had a similar problem when I was using Provider Hosted. The App Web for me wasn't coming over because I tried to use a certificate that would not work (wild card). Went through the certificate setup a second time using a self-signed certificate - then setup a dummy list and when I looked at:
string spAppUrl = Request["SPAppWebUrl"];
I'm getting back the proper value. I then use the URL to get your App web via:
System.Security.Principal.WindowsIdentity currentUser = Request.LogonUserIdentity;
using (var appContext = TokenHelper.GetS2SClientContextWithWindowsIdentity(appUri, currentUser))
{
if (appContext != null)
{
Web appWeb = appContext.Web;
appContext.Load(appWeb, w => w.Title);
appContext.ExecuteQuery();
string title = appWeb.Title;
ViewBag.SiteTitle = title;
}
}
Had exactly the same issue. The following blog post tells you how to resolve it:
SP Rest Services with Provider hosted app
Basically, since a provider-hosted app doesn't have and app web, you have to tell sharepoint to create it. You do this by adding a dummy object (site column, list, etc) to your SharePoint project. It will then create the app web and add SPAppWebUrl to the standard tokens (in the app manifest).
Related
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 ...
I am trying to set up Strava authentication (which is plain oAuth2) in Asp.Net Core Blazor App.
I am rather new to Blazor & Web dev (more of a backend background), and I don't seem to find out how to troubleshoot the reason why the Authentication does not work.
When I click the oAuth login button on the Login page in the (default) Blazor Server App, I get redirected to the correct oAuth login screen (of Strava in my case), but after I successfully enter the credentials for that App, the login page shows an error Error loading external login information.
While I would obviously appreciate any help or tips that could point out what is wrong in my code, I'm mostly searching for a way to get better error information and troubleshooting capabilities here. Setting a breakpoint in the EventHandler delegates does not show much.
This is the Startup.cs extract where I have configured the authentication setup :
services.AddAuthentication().AddOAuth("Strava",
oAuthOptions =>
{
oAuthOptions.ClientId = "myappid";
oAuthOptions.ClientSecret = "myclientsecret";
oAuthOptions.Scope.Clear();
oAuthOptions.Scope.Add("read");
oAuthOptions.CallbackPath = "/profile";
oAuthOptions.AuthorizationEndpoint = "https://www.strava.com/oauth/authorize";
oAuthOptions.TokenEndpoint = "https://www.strava.com/api/v3/oauth/token";
oAuthOptions.SignInScheme = IdentityConstants.ExternalScheme;
oAuthOptions.Events = new OAuthEvents()
{
OnRemoteFailure = loginFailureHandler =>
{
Console.WriteLine("Remote Error");
Console.WriteLine(loginFailureHandler.Failure.Message);
return Task.FromResult(0);
},
OnAccessDenied = handler =>
{
Console.WriteLine(handler.Response.StatusCode);
return Task.FromResult(0);
}
};
});
An update that made things work for me, so maybe it can help other people.
I performed the following actions, in order to gain more control on the entire authentication process.
I scaffolded two pages, in which I then could debug & step through (and obviously also update and change things). More information was found in this post:
Account.Login, which enables the customization of the actual login page dotnet aspnet-codegenerator identity -dc CotacolApp.Data.ApplicationDbContext --files "Account.Login"
Account.ExternalLogin, which enables the customization of the actual strava page dotnet aspnet-codegenerator identity -dc CotacolApp.Data.ApplicationDbContext --files "Account.ExternalLogin"
I then found out that the var info = await _signInManager.GetExternalLoginInfoAsync(); always resulted in a null value. And that was because I had to set the IdentityScheme to external. ```
And after that, I had to run some custom logic to do the claim mapping. Most of those details were written down in this stackoverflow post by #Morgeh.
Hope this can help people in the future.
I have a relatively old Asp.net mvc web project (created around 2012) which used Facebook connect using the AuthConfig.cs file and registered a client as so.
OAuthWebSecurity.RegisterFacebookClient(
appId: WebConfigurationManager.AppSettings["facebookOAuthAppID"],
appSecret: WebConfigurationManager.AppSettings["facebookOAuthAppSecret"]
);
Up until a few days ago when Facebook changed to v2 of their API, all was good but now all is dead when I try to connect. This is where it fails in the account controller.
DotNetOpenAuth.AspNet.AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
Result always returns false, so never continues.
I have found a few examples which inherit IAuthenticationClient and allow you to setup additional scopes etc, and these expose the endpoints that facbook uses. I tried to update these urls to use the new API (v2.3) but still the same error.
Has anyone encountered this and what steps did you do to resolve this?
I keep getting a 500 error when trying to create the ODataClient and passing in ODataSettings with new NetworkCredentials(username, password). Anyone have any examples of creating this service with Basic Authentication?
I enabled basic authentication for a sample OData Web site, and then I was able to access it using Simple.OData.Client and the following code:
var settings = new ODataClientSettings();
settings.UrlBase = "http://localhost/ProductService/odata";
settings.Credentials = new NetworkCredential("Tester", "tester123");
var client = new ODataClient(settings);
If it doesn't work for you I suggest you check if it works when you disable basic authentication and open the site for anonymous access. If it still doesn't work, then the problem is with something else. Otherwise let me know what platform and Simple.OData.Client version you are using (I tested on .NET 4.0, .NET 4.5 and Simple.OData.Client v.2.0.0).
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)