UrlHelper doesn't use referrer host when generating URIs - c#

I am developing an MVC Web API application that I need to access from web browsers on many different devices, for example, smart phones. During development I want to be able to debug while I access the site from my phone. To do this, I have set up Fiddler to provide a reverse proxy. Locally, the server is running on localhost:55950, but from my phone I can access the site as MyComputer:8888. This part is working.
The issue is that I am creating URIs in my REST responses. When I access the site at MyComputer:8888, I need the URIs to be something like MyComputer:8888/services/api/files, but instead I get localhost:55950/services/api/files, which fails on my phone. I am using the UrlHelper class to generate the URIs. I've looked all over, but haven't found a way to tell the system to use the referrer, not the local host. I see the desired Referrer value in the Request, so I think I could write code to patch the URI, but it seems like this would be a common issue and that there must be a way to get UrlHelper to work correctly.
I'd greatly appreciate it if anyone could point me in the right direction.

Check out this SO answer.
var httpContext = HttpContext.Current;
if (httpContext == null) {
var request = new HttpRequest("/", "http://example.com", "");
var response = new HttpResponse(new StringWriter());
httpContext = new HttpContext(request, response);
}
var httpContextBase = new HttpContextWrapper(httpContext);
var routeData = new RouteData();
var requestContext = new RequestContext(httpContextBase, routeData);
return new UrlHelper(requestContext);

Related

Unable to sign in to login.microsoftonline.com oauth 2 authorize endpoint

I've tried different ways to connect the Microsoft sign in function which open a webpage so you can use things like sign in with MFA. I manage to get this to work in Postman and now im trying it in C# particularly in .NET MVC 5.
HomeController:
public ActionResult TestAuth()
{
HttpClient client = new HttpClient();
var bodyParams = new Dictionary<string, string>();
bodyParams.Add("client_id", "{my_client_id}");
bodyParams.Add("client_secret", "{my_client_secret}");
bodyParams.Add("scope", "openid");
bodyParams.Add("redirect_uri", "https://localhost");
bodyParams.Add("grant_type", "authorization_code");
var response = client.PostAsync("https://login.microsoftonline.com/{my_tenant_id}/oauth2/v2.0/authorize", new FormUrlEncodedContent(bodyParams)).Result;
return View("TestAuth", new { response.Content.ReadAsStringAsync().Result });
}
View TestAuth.cshtml:
#model dynamic
#Html.Raw(Model)
If i sign in with my email on that domain, or any text at all really, i get this message. I cannot see why this issue occurs it gives me zero information what to do next more than just trying until you make it basically :). I've looked at tons of different Microsoft documentations, Stack posts, forums etc but with no success.
The postman call example:
Is it possible I'm doing something wrong in the request in the c# code or am i missing something important like configurations in Azure AD etc?
I'm up for anything that will work that i can sign into a Microsoft account that use MFA, then i can use their login to fetch data from Microsoft Graph based on their permissions basically.
P.S. I also can fetch data with the access token generated from postman so it's working as expected. I only need to "convert the postman call to c#" to make it work esentially. Any help is appreciated :)
You’re trying to do an oauth2 request from the controller. The request you’re sending is incorrect.
Microsoft made a great sample on how to use the Microsoft identity platform in a dotnet application https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/1-WebApp-OIDC
In a nutshell you redirect the user to the endpoint (so not a get/post from the controller, but actually a redirect 302 response to the token url).
The user then has to login and is redirected to the webapplication.
Your webapplication will get an authorization code that is has to exchange for an access token by a post request.
Postman does this for you, but in order to do it in dotnet core, just follow the sample.
I didn't find a soultion to this specific problem what i did find was another guide which led me to this github project https://github.com/Azure-Samples/ms-identity-aspnet-webapp-openidconnect
Which had similar code in the Startup.cs file but actually had some examples like SendMail and ReadMail etc which was fetched from ms graph api. This gave me some idea of how this project was structured compared to mine. So one thing that was missing was this part I couldnt figure out:
IConfidentialClientApplication app = await MsalAppBuilder.BuildConfidentialClientApplication();
var account = await app.GetAccountAsync(ClaimsPrincipal.Current.GetAccountId());
So the Msal app builder which is a custom made thingy i needed to get the current user etc which i needed. This works fine and after that i can start doing requests to the graph api like adding scopes etc and make http request.
Example see groups:
[Authorize]
[HttpGet]
public async Task<ActionResult> GetGroups()
{
IConfidentialClientApplication app = await MsalAppBuilder.BuildConfidentialClientApplication();
var account = await app.GetAccountAsync(ClaimsPrincipal.Current.GetAccountId());
string[] scopes = { "GroupMember.Read.All", "Group.Read.All", "Group.ReadWrite.All", "Directory.Read.All", "Directory.AccessAsUser.All", "Directory.ReadWrite.All" };
AuthenticationResult result = null;
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/groups");
try
{
//Get acccess token before sending request
result = await app.AcquireTokenSilent(scopes, account).ExecuteAsync().ConfigureAwait(false);
if (result != null)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
//Request to get groups
HttpResponseMessage response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
ViewBag.Groups= response.Content.ReadAsStringAsync().Result;
return View("MyView");
}
}
}
catch (Exception ex)
{
Response.Write($"Error occured:{System.Environment.NewLine}{ex}");
}
return View();
}

Google PageSpeed API dotnet .net

I have set up a basic C# application to run a PageSpeed test on a website that I specify using the Google.Apis.Pagespeedonline.v2 nuget package.
The set up is simple enough and I have a variable that I can specify the url which is then past in to the Service
// Create the service.
var service = new PagespeedonlineService(new BaseClientService.Initializer
{
ApplicationName = "PageSpeed Sample",
ApiKey = "[API_KEY_HERE]"
});
var url = "URL_TO_TEST";
// Run the request.
var result = await service.Pagespeedapi.Runpagespeed(url).ExecuteAsync();
The problem being the .Runpagespeed method ONLY accepts URL. I need to be able to specify, at minimum, the 'Mobile' strategy so I can obtain scores for both Desktop and Mobile. I know this is possible in other libraries but seems to be missing in .NET. Is anybody aware of a way to do this using the .NET library? In the reference documentation it implies that the method accepts further optional parameters but it does not in the code.
Pagespeedapi: runpagespeed has an optional value called strategy
strategy string The analysis strategy to use
Acceptable values are: "desktop": Fetch and analyze the URL for
desktop browsers "mobile": Fetch and analyze the URL for mobile
devices
Example:
var request = service.Pagespeedapi.Runpagespeed(url);
request.Strategy = Google.Apis.Pagespeedonline.v2.PagespeedapiResource.RunpagespeedRequest.StrategyEnum.Mobile;
var results = request.Execute();

how to use box api in asp.net web application

I am trying to use box api in an asp.net web application.
Based on the search there are two options to access box account;
By downloading the Box.V2 package using below link containing the required dlls and use that in our application
By using Box SDK containing code and reference that inside our application. Using this approach we can debug the Box.V2 code by adding the project to our solution.
Correct me if I am wrong.
So, I am trying to implement the second approach. Can someone help me move forward by specifying the steps to be taken, minimum .net framework requirement, etc.
Good question, GitHub samples does not mention about the Web (Asp.Net).
It's possible and it looks pretty easy to do once you figure out the the way,
I have seen some answers for Windows apps trying to manually build the authorization URLs etc, but there is an easier way to do it.
Here's how to do it with OAuth,
Install nuget
PM> Install-Package Box.V2
Get the Authcode (this is what's been missing in most examples)
public async Task<ActionResult> Connect()
{
var clientId = "xxxxx";
var clientSecret = "xxxxxx";
var redirectUri = new Uri("http://localhost:xxxx/Home/AuthCallBackAsync");//Your call back URL
var config = new BoxConfig(clientId, clientSecret, redirectUri);
return Redirect(config.AuthCodeUri.ToString());
}
Interesting thing is that the "config" object generates the AuthCodeUri.
This will redirect the user to Consent screen and ask the user to sign in. Once the user "Grants Access" you will get the "Authcode" for your call back URL which can be used to generate accesstoken.
Handle the Auth Callback response
public async Task<ActionResult> AuthCallbackAsync()
{
NameValueCollection parms = Request.QueryString;
var authCode = parms["code"]
//Get "config" - you can store this in session or in a cache.
var config = new BoxConfig(clientId, clientSecret, redirectUri);
var client = new BoxClient(config);
await client.Auth.AuthenticateAsync(authCode);
//Now you will get the accesstoken and refresh token
var accessToken = client.Auth.Session.AccessToken;
var refreshToken = client.Auth.Session.RefreshToken;
//Ready to consume the API
var user = await client.UsersManager.GetCurrentUserInformationAsync();
-------More Api Calls---
}

WebView Source - automatic authentication

I am looking for a way to automatically authenticate for a web site.
I've got a WebView in my c# Windows Store App and I want to access a site that is password protected.
WebView.Source= new URI("http://UserId:Password#foo.com/");
This is not working as I get a Security exception:
A security problem occurred. (Exception from HRESULT: 0x800C000E);
The method below is also not working as I only get the html of a site, but no css or JavaScript:
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials = new NetworkCredential("UserId", "Password");
HttpClient client = new HttpClient(handler);
string body = await client.GetStringAsync("http://foo.com");
webview.NavigateToString(body);
Is there any other way?
I have came across same problem, but luckily found an answer :)
Main problem in here is that Windows store applications contain 2 different HttpClient's
One of them is "classic" one we know from c# apps (used automatically) and the other one is "new" HttpClient - which is connected with WebView :)
Bellow are both types :
System.Net.Http.HttpClient ( classic one )
Windows.Web.Http.HttpClient ( new one )
So remember to declare the new One and do something like the code bellow
var filter = new HttpBaseProtocolFilter();
filter.ServerCredential = new Windows.Security.Credentials.PasswordCredential("http://website","login", "password");
Windows.Web.Http.HttpClient client2 = new Windows.Web.Http.HttpClient(filter);
var response = await client2.GetAsync(new Uri("http://website"));
WebView.Source = new Uri("http://website");
Now remember to change login and password to credentials you want to use, and a website is a site you want to authenticate to.
It is important to get the response from server - this will make user authenticated # server so next time you go with webView to that site you will be authenticated
It works fine with basic authentication and NTLM authentication
Hope it will help people searching for solution of this problem :)

How to retrive records from OData service of crm 2011 IFD

I have the fallowing code.
var ctx = new XrmContext(new Uri(serviceUrl));
ctx.Credentials = new NetworkCredential("username", "password", "domain");
ctx.AccountSet.First();
Silverlight version is (In fiddler we have here the same result)
var ctx = new AdzzContext(new Uri(serviceUri));
ctx.HttpStack = System.Data.Services.Client.HttpStack.ClientHttp;
ctx.UseDefaultCredentials = false;
ctx.Credentials = new NetworkCredential("username", "password", "admin");
var query = ctx.AccountSet;
var async = new DataServiceCollection<Account>();
async.LoadCompleted += async_LoadCompleted;
async.LoadAsync(query);
What give me the falling error.
The response payload is a not a valid response payload. Please make
sure that the top level element is a valid Atom element or belongs to
'http://schemas.microsoft.com/ado/2007/08/dataservices' namespace.
When I look at fiddler I see a redirect to the adfs server
I saw this link, but it is for CRM 4, And in the context of the OData I can't put a token.
My target is so,
To make a Silverlight library for business logic (BL) purpose - So I can debug it easily in my computer - and it will run perfectly in the CRM environment,
How can I do it?
you need to generate the early bound classes (using crmsvcutil.exe) and specify the ServiceContextName parameter.
Assuming your context is XrmContext, you need to instantiate in this way:
var context = new XrmContext(service);
where service is the IOrganizationService web service.
You don't need to specify the credentials because the connection credentials are handled when you instantiate the OrganizationServiceProxy
Sample code: http://nishantrana.wordpress.com/2010/11/03/sample-code-for-using-iorganizationservice-in-crm-2011/

Categories

Resources