Why is Page_Load fired a second time after RequestUserAuthorization? - c#

I'm testing the "OAuth/OAuth2/OAuthClient/Facebook.aspx" file from the DotNetOpenAuth.Samples solution.
here is the code (Simple authentication from Facebook directly in the PageLoad) :
namespace OAuthClient {
using System;
using System.Configuration;
using System.Net;
using System.Web;
using DotNetOpenAuth.ApplicationBlock;
using DotNetOpenAuth.ApplicationBlock.Facebook;
using DotNetOpenAuth.OAuth2;
public partial class Facebook : System.Web.UI.Page {
private static readonly FacebookClient client = new FacebookClient {
ClientIdentifier = ConfigurationManager.AppSettings["facebookAppID"],
ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(ConfigurationManager.AppSettings["facebookAppSecret"]),
};
protected void Page_Load(object sender, EventArgs e)
{
IAuthorizationState authorization = client.ProcessUserAuthorization();
if (authorization == null)
{
// Kick off authorization request
client.RequestUserAuthorization();
}
else
{
var request = WebRequest.Create("https://graph.facebook.com/me?access_token=" + Uri.EscapeDataString(authorization.AccessToken));
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
var graph = FacebookGraph.Deserialize(responseStream);
this.nameLabel.Text = HttpUtility.HtmlEncode(graph.Name);
}
}
}
}
}
}
When the Page_Load is firing for the first time, authorization == null, so the client.RequestUserAuthorization(); call is executed, and then, Page_load is firing a second time.
Why ? I don't understand the mecanism.
I used fiddler to sniff the response sent back by facebook after "client.RequestUserAuthorization()", but it's always an empty body.
My final goal is to launch the authenfication process from a button. But when the "client.RequestUserAuthorization();" call is executed within a button, nothing is fired a second time... so authorization is always null.

Related

Pass header cookies from Web API post to header location page

I have an ASP.Net Web API that is posted to from an external source. The values that are posted to the web api are used to determine the user's rights on our website. So the web api then passes the result object of my business logic as a bunch of cookies to our asp landing page. The problem is that the cookies are no longer available in the web page that the web api routed the response to.
Here is web api:
[HttpPost]
public HttpResponseMessage Reports(ReportRequest reportRequest)
{
if (reportRequest != null)
{
var reportAccess = new SwitchBL().CheckUserAccess(reportRequest);
var response = Request.CreateResponse(HttpStatusCode.Moved);
response.Headers.Location = new Uri(BaseUrl() + "/menu.aspx");
var json = JsonConvert.SerializeObject(reportAccess);
Dictionary<string, string> biscuitTin = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
foreach (var biscuit in biscuitTin)
{
var cookie =
new CookieHeaderValue(biscuit.Key, biscuit.Value ?? "")
{
Expires = DateTimeOffset.Now.AddDays(1),
Domain = Request.RequestUri.Host == "localhost" ? null : Request.RequestUri.Host,
HttpOnly = true
};
//cookierJar.Add(cookie);
response.Headers.AddCookies(new CookieHeaderValue[] {cookie} );
}
return response;
}
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
And so far my very simple aspx page always shows count = 0:
public partial class menu : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var cookieCount = Request.Cookies.Count;
}
}
The web api and aspx pages are in the same project thus hosted in one site. I do not want to use session variables and do not want to pass values in querystrings. Is there another way of passing data to the routed page from the web api or am I missing something here?
BTW, if I post to the api using Postman, the cookies are visible in the response header of the web api, so cookies are created. If I post using another web page, using Fiddler, I can see the cookies in the response of the api but then there are no cookies in the (receiving) asp page.
UPDATE
Thanks to the answer of Kai, I can now get the cookies in my route asp page as set in response.Headers.Location. I have a breakpoint in that page so I know it is being hit and cookie count is now as expected. However, the browser does not render the routed page. It remains on the original posting page. Here is the code I'm using in my post emulator page to call the web api:
protected void Page_Load(object sender, EventArgs e)
{
}
protected async void DoIt_OnClick(object sender, EventArgs e)
{
var reportRequest = new ReportRequest();
reportRequest.EmailAddress = Email.Text;
reportRequest.UserNumber = UserCode.Text;
reportRequest.MobileNumber = MobileNumber.Text;
reportRequest.Password = Password.Text;
reportRequest.Country = Country.Text;
reportRequest.AccountNumber = AccountNumber.Text;
reportRequest.AccountType = AccountType.Text;
reportRequest.ReportType = ReportType.Text == "" ? 0 : Convert.ToInt32(ReportType.Text);
reportRequest.PhoneInfo = PhoneInfo.Text;
await GoThereAsync(reportRequest);
}
public async Task<Uri> GoThereAsync(ReportRequest reportRequest)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:7789/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
var response = await client.PostAsJsonAsync<ReportRequest>("api/switch/reports", reportRequest);
if (response.IsSuccessStatusCode)
{
return response.RequestMessage.RequestUri;
}
return null;
}
}
To summarise: Emulator.aspx does POST to web api. Web API sets cookies and location to home.aspx. Home.aspx receives cookies (debug steps into code-behind) but browser remains on Emulat.aspx and does not render home.aspx.
Try CookieHeaderValue.Path = "/".
From the Microsoft Docs:
Path: Restricts the cookie to the specified path within the domain. If not specified, the path of the request URI is used.

HttpClient (Windows.Web.Http) working with cookies

I am working on a Windows app and am having some issues with cookies. Please note that I am working with Windows.Web.Http, not the System namespace HttpClient.
The API I'm working with uses an auth-header for authentication. Basically after a POST to login, I need a way to get the cookies returned and then use those cookies to perform the subsequent API calls. I posted an example of what I currently have, which succeeds. I can see the cookies in the result object. I'm just not entirely sure where to go from here / how to proceed. Thanks! Any ideas?
using MyApi.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Web.Http;
using Newtonsoft.Json;
using MyApi.Models.Auth;
using MyApi.Models;
namespace MyApi
{
public class MyService
{
private const string MyBaseUrl = "http://api.my.com:3000";
private readonly HttpClient _httpClient = new HttpClient();
public async Task<SignInResponse> AttemptLogin(string username, string password)
{
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
throw new ArgumentException("Username or password is null or empty");
var uri = new Uri(string.Format("{0}/{1}", MyBaseUrl, "auth/signin"));
var authSignIn = new Models.Auth.SignInRequest();
authSignIn.Email = username;
authSignIn.Password = password;
var myObject = JsonConvert.SerializeObject(authSignIn);
// I see the headers in the result object, but I'm not
// sure the best way to a) get them out and b) shove them into
// all of the next calls
var result = await _httpClient.PostAsync(uri,
new HttpStringContent(myObject.ToString(),
Windows.Storage.Streams.UnicodeEncoding.Utf8,
"application/json"));
var content = await result.Content.ReadAsStringAsync();
var successResponse = new SignInResponse();
try
{
successResponse = JsonConvert.DeserializeObject<SignInResponse>(content);
}
catch (Exception)
{
var failResponse = JsonConvert.DeserializeObject<ErrorResponse>(content);
throw new Exception(failResponse.message);
}
return successResponse;
}
}
}
You can use HttpBaseProtocolFilter.CookieManager, e.g.:
var filter = new HttpBaseProtocolFilter();
var cookieManager = filter.CookieManager;
var uri = new Uri("http://api.my.com:3000");
foreach (var cookie in cookieManager.GetCookies(uri))
{
Debug.WriteLine(cookie.Name);
Debug.WriteLine(cookie.Value);
}
Notice, if the cookies are already in the HttpCookieContainer, the cookies will be automatically added in the next requests to http://api.my.com:3000, and no action is required from your side.
If you want to modify them or delete them, the HttpCookieContainer has methods to do that.
Take a look at Flurl. It presents a fluent interface over the Http bits, so you can say something like this to authenticate and reuse the connection with the cookies:
using (var fc = new FlurlClient().EnableCookies())
{
var url = new Url( "http://api.com/endpoint" ) ;
await url
.AppendPathSegment("login")
.WithClient(fc)
.PostUrlEncodedAsync(new { user = "user", pass = "pass" });
var page = await url
.AppendPathSegment("home")
.WithClient(fc)
.GetStringAsync();
// Need to inspect the cookies? FlurlClient exposes them as a dictionary.
var sessionId = fc.Cookies["session_id"].Value;
}

How to create VMs using google compute engine REST API

I am new to Google Compute Engine. Some one please help me with creating Google Compute Engine VMs programmatically using REST APIs in C#.
Here [1] you can found the API documentation to create an instance and at the bottom of the document the C# examples [2]:
using Google.Apis.Auth.OAuth2;
using Google.Apis.Compute.v1;
using Google.Apis.Services;
using Newtonsoft.Json;
using System;
using System.Threading.Tasks;
using Data = Google.Apis.Compute.v1.Data;
namespace ComputeSample
{
public class ComputeExample
{
public static void Main(string[] args)
{
ComputeService computeService = new ComputeService(new BaseClientService.Initializer
{
HttpClientInitializer = GetCredential(),
ApplicationName = "Google-ComputeSample/0.1",
});
// Project ID for this request.
string project = "my-project"; // TODO: Update placeholder value.
// The name of the zone for this request.
string zone = "my-zone"; // TODO: Update placeholder value.
// TODO: Assign values to desired properties of `requestBody`:
Data.Instance requestBody = new Data.Instance();
InstancesResource.InsertRequest request = computeService.Instances.Insert(requestBody, project, zone);
// To execute asynchronously in an async method, replace `request.Execute()` as shown:
Data.Operation response = request.Execute();
// Data.Operation response = await request.ExecuteAsync();
// TODO: Change code below to process the `response` object:
Console.WriteLine(JsonConvert.SerializeObject(response));
}
public static GoogleCredential GetCredential()
{
GoogleCredential credential = Task.Run(() => GoogleCredential.GetApplicationDefaultAsync()).Result;
if (credential.IsCreateScopedRequired)
{
credential = credential.CreateScoped("https://www.googleapis.com/auth/cloud-platform");
}
return credential;
}
}
}
[1] https://cloud.google.com/compute/docs/reference/rest/v1/instances/insert
[2] https://cloud.google.com/compute/docs/reference/rest/v1/instances/insert#examples

Way to get ALL cookies created in Awesomium? (including Http)

I'm using the Awesomium .NET API to log in to http://www.habbo.com using the username and password provided by the user in a text box. The issue I have is that to send further requests (eg. navigate to a room - Habbo is an online game) via Http I need to send the same cookies, otherwise it doesn't work.
I'm trying to send the navigate request using this code:
using (WebClient WC = new WebClient())
{
WC.Headers["X-App-Key"] = Token;
WC.DownloadString(new Uri(string.Format("http://www.habbo.com/components/roomNavigation?targetId={0}&roomType=private&move=true", roomID)));
}
I need to attach the Http cookies to WC in order for it to be successful. I'm logging in to http://www.habbo.com using this code:
public int Timer = 0;
public void AttemptLogin_Tick(object sender, EventArgs e)
{
Timer++;
if (Timer == 1)
{
webControl1.Source = new Uri("http://www.habbo.com/client");
}
if (Timer == 3)
{
webControl1.Source = new Uri(string.Format("https://www.habbo.com/account/submit?credentials.username={0}&credentials.password={1}", username2, password2));
}
if(Timer == 6)
{
webControl1.Source = new Uri("http://www.habbo.com/client");
}
}
I know I can get some of the cookies using
webControl1.ExecuteJavascriptWithResult("document.cookie;");
but this doesn't get the Http ones I need also. The cookies are unique to each session, so as far as I'm aware using HttpWebRequest to get them would result in different Http cookies to the ones I need (and therefore log me out if I tried sending them instead, as it would indicate I had two sessions logged in).
Does anyone have any ideas? Thanks.

How to solve System.NullReferenceException

I am calling a web service in my php page. The web services are in C#. When I try to call a method using soap client object, it displays me error like:
System.NullReferenceException: Object reference not set to an instance of an object.
The code I use to call Web service method is :
$Username = "username";
$Password = "password";
$LifetimeRequest = 60*60*24;
$soap_data = array(
'Username' => $Username,
'Password' => $Password,
'LifetimeRequest' => $LifetimeRequest
);
$client = new SoapClient('http://50.56.173.161:8502/AdomniService.svc?wsdl');
$response = $client->ClientLogin($soap_data);
var_dump($response);
When I use var_dump it shows output like:
object(stdClass)#2 (1) {
["ClientLoginResult"]=>
object(stdClass)#3 (3) {
["Error"]=>
object(stdClass)#4 (5) {
["Private"]=>
float(2)
["Public"]=>
int(1)
["Details"]=>
string(284) "System.NullReferenceException: Object reference not set to an instance of an object.
at Adomni.AdomniService.ClientLogin(ClientLoginRequest request) in C:\Users\megiddo\Documents\Visual Studio 2010\Projects\Adomni\AdOmniAPIService\AdomniService\AdomniClientService.svc.cs:line 107"
["ErrorCode"]=>
int(0)
["ErrorMessage"]=>
NULL
}
["Status"]=>
int(-1)
["Token"]=>
object(stdClass)#5 (8) {
["Private"]=>
float(2)
["Public"]=>
int(1)
["EventNotificationUri"]=>
NULL
["IsManager"]=>
bool(false)
["LifetimeRequest"]=>
int(0)
["Password"]=>
NULL
["TokenId"]=>
int(0)
["UserName"]=>
NULL
}
}
}
Can anyone tell me what am I doing wrong here? Thanks in advance.
The code which was used in C# is like:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using System.Web.Security;
using System.IO;
using System.Data;
using AdOmniWebPortal.AdOmniService;
namespace AdOmniWebPortal
{
public partial class Login : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void AdOmniLogin_Authenticate(object sender, AuthenticateEventArgs e)
{
AdomniServiceClient Client = new AdomniServiceClient();
LoginRequest LoginRequest = new LoginRequest();
LoginResponse LoginResponse = new LoginResponse();
LoginRequest.Username = AdOmniLogin.UserName;
LoginRequest.Password = AdOmniLogin.Password;
LoginRequest.LifetimeRequest = 60*60*24;
//This guy will be changed
LoginRequest.EventNotificationURL = new Uri("http://herp-a-derp.com/awesome.html");
LoginResponse = Client.Login(LoginRequest);
if (LoginResponse.Status == 0)
{
System.Web.Security.FormsAuthentication.RedirectFromLoginPage(LoginResponse.Token.UserName, true);
LifetimeToken token = LoginResponse.Token;
Session["Token"] = token;
GetUserRequest request = new GetUserRequest() { Token = token };
GetUserResponse response = Client.GetUser(request);
if (response.GetUser.Type == AdOmniService.UserType.Seller)
{
Response.Redirect("~/Pages/Seller/SellerHomeDashboard.aspx");
}
if (response.GetUser.Type == AdOmniService.UserType.Client)
{
Response.Redirect("~/Pages/Buyer/BuyerHomeDashboard.aspx");
}
if (response.GetUser.Type == AdOmniService.UserType.None)
{
Response.Redirect("~/Pages/Buyer/BuyerHomeDashboard.aspx");
}
}
else
{
Response.Redirect("~/Login.aspx");
Response.Write(LoginResponse.Error.ErrorMessage);
}
}
}
}
I have put the whole .cs page content in Edit.
Use Fiddler (a http debug proxy)
that will allow you to peak inside of the request being made to the web service (in xml format)
so you can see if you are missing anything.
channel your c# client through fiddler, and take a look
http://www.fiddler2.com/fiddler2/
Maybe in your PHP script, you should also set the EventNotificationURL variable.
Take a look at this section in the error response:
["EventNotificationUri"]=>
NULL
Maybe the service expects you to pass in a EventNotificationUri value, just like you pass in the the Password, Username and LifetimeRequest.
[EDIT]
Try to change your variable name from Username to UserName. As far as I found out, PHP should be case sensitive in this matter, so "Username" != "UserName"

Categories