I want to sign in to youtube with post request. I used xNet for HttpRequest.
I wrote following codes:
static void Main(string[] args)
{
string url = "https://accounts.google.com/_/signin/sl/lookup?hl=en&_reqid=55174&rt=j";
HttpClass httpClass = new HttpClass();;
httpClass.PostRequestAsync(url, "username", "password");
}
class HttpClass {
public async Task PostRequestAsync(string url, string account, string pass)
{
xNet.HttpRequest http = new xNet.HttpRequest();
http.Cookies = new CookieDictionary();
string type = "application/x-www-form-urlencoded;charset=utf-8";
string query =
"continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Ffeature%3Dsign_in_button%26action_handle_signin%3Dtrue%26app%3Ddesktop%26next%3D%252F%26hl%3Den&service=youtube&hl=en&f.req=%5B%22" + account + "%22%2C%22AEThLlxFJqXTI-dLw8jxU_Lw8c4Qtpc4DAAeEE1rpkbEUFqwwK1U86bZEzsWmZKM5IjRccPvbYTLgb0yonB3vputyMTNm-8YcGqbe_GeaB6RHFJImp_gZ-y0jFv4nduPGxM-zpJX8BahbDlIyeY2sP8-puVe3W1iwKX3rGcSFGMevHHK-ByNEUY%22%2C%5B%5D%2Cnull%2C%22TR%22%2Cnull%2Cnull%2C2%2Cfalse%2Ctrue%2C%5Bnull%2Cnull%2C%5B2%2C1%2Cnull%2C1%2C%22https%3A%2F%2Faccounts.google.com%2FServiceLogin%3Fuilel%3D3%26passive%3Dtrue%26service%3Dyoutube%26continue%3Dhttps%253A%252F%252Fwww.youtube.com%252Fsignin%253Ffeature%253Dsign_in_button%2526action_handle_signin%253Dtrue%2526app%253Ddesktop%2526next%253D%25252F%2526hl%253Den%26hl%3Den%22%2Cnull%2C%5B%5D%2C4%2C%5B%5D%2C%22GlifWebSignIn%22%5D%2C1%2C%5Bnull%2Cnull%2C%5B%5D%5D%2Cnull%2Cnull%2Cnull%2Ctrue%5D%2C%22" + account + "%22%5D&bgRequest=%5B%22identifier%22%2C%22!Pj2lPRxCiup4YICaVSxEHyFXdsNE5lECAAAAQ1IAAAAbCgAW9I8p8C1f10xg_NjCyA99rybP30APm5kBCr5B19mb-UkpwTj1ZsyybospA0TSjuUTuJeCHmkiRqKfhHxRE1CV0Yd7nifpK8VCTMNnmUMrl4-anneYlV-Bs3NQESEmJTEcxBOjvbo_tXSasO8KbZopdTxzUHm-qBGOQRTUZM4Hw6x-1HJdLoCQ2bi4FoAhbsWEt6paR0K4neYHS1kdxewjDKefWWCQ__O3C71yOjm6p0S1rjNUEM0ak9V8N2CcnIFYQ77b1B98nHCZmgMr81YtgAOF8ClSb4ZV8AiUc96rC1rvMV2RIvW54RUgsJwWHXBx0nid8tRMdUmzCTymoa-_at7qE1nJL8SMAU9WEnGOs0u2xKlBKGsjNgnqhligTDBDPnp7%22%5D&azt=AFoagUUuZ6teJ3APaa8f6ly_olQZHdGWBg%3A1525177142108&cookiesDisabled=false&deviceinfo=%5Bnull%2Cnull%2Cnull%2C%5B%5D%2Cnull%2C%22TR%22%2Cnull%2Cnull%2C%5B%5D%2C%22GlifWebSignIn%22%2Cnull%2C%5Bnull%2Cnull%2C%5B%5D%5D%5D&gmscoreversion=undefined&checkConnection=youtube%3A288%3A1&checkedDomains=youtube&pstMsg=1&";
string html;
html = http.Post(url, query, type).ToString();
htmlTest(html);
type = "application/x-www-form-urlencoded";
query =
account +
"&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Ffeature%3Dsign_in_button%26action_handle_signin%3Dtrue%26app%3Ddesktop%26next%3D%252F%26hl%3Den&password=" +
pass + "&ca=&ct=";
http.Cookies = new CookieDictionary();
html = http.Post(url, query, type).ToString();
htmlTest(html);
}
public void htmlTest(string html)
{
File.WriteAllText("a.html", html);
Process.Start("a.html");
}
}
Response is:
)]}' [[["er",null,null,null,["gf.rrerr",1,"https://support.google.com/accounts/answer/61416?hl\u003den"] ,null,"gf.rrerr"] ,["e",2,null,null,149] ]]
The given link "https://support.google.com/accounts/answer/61416?hl\u003den" is says you must to open your cache data. I think I need to pass cookies with post but How can I pass cookies with post request?
Try to use cookíe with code
request.Cookies = new CookieDictionary()
{
{"ggg", "hhh"}
};
Related
I am a begginer and i work in a MVC project which I cant understand it well yet.
I can't understand where does the API takes data from when I try to connect in Login Screen.
It doesn't use Entity Framework and there isn't a json with the data.
When I enter Id and Pass it calls an API (GetAPIResponse) which somehow finds that is correct.
Need help to understand the code and the logic behind it.
LoginBL class contains:
public bool IsAuthenticated(LoginEntity user)
{
string url = string.Empty;
string callType = string.Empty;
string server = string.Empty;
try
{
// get URL, Call type, Server from config file
url = ConfigurationManager.AppSettings["login_url"].ToString();
callType = ConfigurationManager.AppSettings["calltype"].ToString();
server = ConfigurationManager.AppSettings["server"].ToString();
// Encrypt password
string password = Scrambler.GenerateMD5Hash(user.Password);
// Prepare content for the POST request
string content = #"calltype=" + callType + "&server=" + server + "&user=" + user.UserName + "&pass=" + password + "";
Debug.WriteLine("Callcenter login url: " + content);
HttpResponseMessage json_list = ApiCallBL.GetAPIResponse(url, content);
LoginResponseEntity obj = new LoginResponseEntity();
obj = JsonConvert.DeserializeObject<LoginResponseEntity>(json_list.Content.ReadAsStringAsync().Result);
Debug.WriteLine(callType + " Response: " + json_list.Content.ReadAsStringAsync().Result);
//if API resultCode return 0 then user details and token save in session for further use
if (obj.ResultCode == 0)
{
int restrict = obj.UserInfo.RestrictCallType.HasValue ?
obj.UserInfo.RestrictCallType.Value : 0;
HttpContext.Current.Session["user_id"] = obj.UserInfo.usr_id;
HttpContext.Current.Session["user_name"] = obj.UserInfo.usr_username;
HttpContext.Current.Session["user_group_id"] = obj.UserInfo.UserGroupID;
HttpContext.Current.Session["groupid"] = obj.UserInfo.groupid;
HttpContext.Current.Session["token"] = obj.Token;
HttpContext.Current.Session["web_server_url"] = obj.ServerInfo.web_server_url;
HttpContext.Current.Session["centerX"] = obj.ServerInfo.DefaultGeoX;
HttpContext.Current.Session["centerY"] = obj.ServerInfo.DefaultGeoY;
HttpContext.Current.Session["dateFormat"] = obj.ServerInfo.dateFormat;
HttpContext.Current.Session["currency"] = obj.ServerInfo.currency;
HttpContext.Current.Session["customer_img"] = obj.ServerInfo.customer_img;
HttpContext.Current.Session["groups"] = obj.groups;
HttpContext.Current.Session["restrict_call_type"] = restrict ;
Debug.WriteLine("obj.UserInfo.UserGroupID " + obj.UserInfo.UserGroupID);
Debug.WriteLine("obj.UserInfo.groups " + obj.groups);
//HttpContext.Current.Session["defaultLanguage"] = obj.ServerInfo.defaultLanguage;
HttpCookie cookie = new HttpCookie("Login");
// if remember me checked then user name and password stored in cookie else cookes is expired
if (user.RememberMe)
{
cookie.Values.Add("user_name", obj.UserInfo.usr_username);
cookie.Values.Add("pwd", user.Password);
cookie.Expires = DateTime.Now.AddDays(15);
HttpContext.Current.Response.Cookies.Add(cookie);
}
else
{
cookie.Expires = DateTime.Now.AddDays(-1);
HttpContext.Current.Response.Cookies.Add(cookie);
}
return true;
}
else
{
//ResultCode -5 :Invalid Login ,-1:Database Error ,-2:Server Error ,-3:Invalid Parameter specified ,-4:Invalid Token
return false;
}
}
catch
{
throw;
}
finally
{
url = string.Empty;
callType = string.Empty;
server = string.Empty;
}
}
Okay here after converts pass to MD5 creates a "string content" with the information given.
Then in next line (HttpResponseMessage json_list = ApiCallBL.GetAPIResponse(url, content);) calls the API with the url and content as parameters where it finds if the data exists.
API code:
public static HttpResponseMessage GetAPIResponse(string url, string content)
{
StringBuilder traceLog = null;
HttpContent httpContent = null;
try
{
traceLog = new StringBuilder();
traceLog.AppendLine("Start: BusinessLayer getAPIResponse() Request Data:- " + DateTime.Now + "URL = " + url + "&content = " + httpContent);
using (HttpClient client = new HttpClient())
{
httpContent = new StringContent(content);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
var resp = client.PostAsync(url, httpContent).Result;
Debug.WriteLine("resp: " + resp.Content.ReadAsStringAsync().Result);
traceLog.AppendLine("End: BusinessLayer getAPIResponse() call completed HttpResponseMessage received");
return resp;
}
}
catch
{
throw;
}
finally
{
traceLog = null;
httpContent.Dispose();
url = string.Empty;
content = string.Empty;
}
}
In the following line, console prints the result that I cant understand where it cames from (Debug.WriteLine("resp: " + resp.Content.ReadAsStringAsync().Result);)
Sorry for the confusion , I am in my first job with zero work experience and I am called to learn how this works alone without proper education on ASP.NET from them.
You will not go very far without debbugger. Learn how to debug in Visual Studio (YouTube tutorials might be fastest way). Place debug points along critical points in code (for example moment when client sends and receives response is line var resp = client.PostAsync...) and check variables.
Url for API server is actually defined in the line
url = ConfigurationManager.AppSettings["login_url"].ToString();
ConfigurationManager means Web.config file, check it's appSettings section for login_url entry, there is your url.
Btw, using (HttpClient client = new HttpClient()) is not a good way to use a HttpClient and will lead to port exhaustion. It's ok for small number of requests, but for larger ones you must reuse it, or use HttpClientFactory (for .NET Core).
I'm trying to access Azure Cosmos DB using Table API.
The challenge is, despite creating SharedKeyLite, server is still returning Unauthorized - seems like SharedKeyLite is not supported or I'm generating the signature or headers wrong.
Here is the code
static readonly string storageAccountName = "accountName";
static readonly string storageAccountKey = "xxxx";
static readonly string uri = "https://accountName.table.cosmosdb.azure.com/Contacts()";
static readonly string utc_date = DateTime.UtcNow.ToString("r");
static void Main(string[] args)
{
Console.WriteLine(GetResult().Result);
}
static async Task<string> GetResult()
{
// Set this to whatever payload you desire. Ours is null because
// we're not passing anything in.
Byte[] requestPayload = null;
var requestDateString = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
var requestUri = new Uri(uri);
DateTime now = DateTime.UtcNow;
//Instantiate the request message with a null payload.
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri)
{ Content = (requestPayload == null) ? null : new ByteArrayContent(requestPayload) })
{
ConstructHeaders(httpRequestMessage.Headers, requestDateString);
string authorizationHeader = GenerateSharedKeyLite(storageAccountKey, storageAccountName, uri,requestDateString);
httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("SharedKeyLite", authorizationHeader);
// Send the request.
using (HttpResponseMessage httpResponseMessage = await new HttpClient().SendAsync(httpRequestMessage))
{
string json = await httpResponseMessage.Content.ReadAsStringAsync();
return json;
}
}
}
These are the headers I"m adding, expansion of ConstructHeaders method.
Refer this link for request parameters
//Construct the headers
static void ConstructHeaders(HttpRequestHeaders headers, string now)
{
headers.Add("x-ms-date", now);
headers.Add("x-ms-version", "2017-04-17");
// If you need any additional headers, add them here before creating
// the authorization header.
headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
if (headers.Contains("DataServiceVersion"))
headers.Remove("DataServiceVersion");
headers.Add("DataServiceVersion", "3.0;NetFx");
if (headers.Contains("MaxDataServiceVersion"))
headers.Remove("MaxDataServiceVersion");
headers.Add("MaxDataServiceVersion", "3.0;NetFx");
}
And this is the method that creates the SharedKeyLite
//Created Shared Key Lite
static string GenerateSharedKeyLite(string accessKey, string account, string url, string date)
{
var uri = new Uri(url);
var canonicalizedResourceString = uri.PathAndQuery;
var queryStart = canonicalizedResourceString.IndexOf('?');
if (queryStart > -1)
{
if (queryStart < canonicalizedResourceString.Length - 1)
{
var path = canonicalizedResourceString.Substring(0, queryStart);
var parameters = HttpUtility.ParseQueryString(canonicalizedResourceString.Substring(queryStart + 1));
var sb = new StringBuilder();
foreach (var keyOri in parameters.Keys)
{
var value = parameters[keyOri];
var key = keyOri.ToLowerInvariant();
sb.Append("\n");
sb.Append(key);
sb.Append(":");
sb.Append(value);
}
canonicalizedResourceString = canonicalizedResourceString + sb.ToString();
}
else
{
canonicalizedResourceString = canonicalizedResourceString.Substring(0, canonicalizedResourceString.Length - 1);
}
}
canonicalizedResourceString = $"/{account}{canonicalizedResourceString}";
var stringToSign = $"{date}\n{canonicalizedResourceString}";
var signedSignature = string.Empty;
using (var hmac = new HMACSHA256(Convert.FromBase64String(accessKey)))
{
var outputBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign));
var signature = Convert.ToBase64String(outputBytes);
return $"{account}:{signature}";
}
}
Any Help? Ideally I want to perform the odata query using simple.odata, but first trying to make this work using HttpClient
Just copy your code and it works on my side. If you haven't modified your code, please make sure your storageAccountName and storageAccountKey are correct.
BTW, in method GenerateSharedKeyLite there's no need to add query parameters to canonicalizedResourceString for entity operation. You only need to add comp if you want to operate component info for table or service. See constructing-the-canonicalized-resource-string.
The query string should include the question mark and the comp parameter (for example, ?comp=metadata). No other parameters should be included on the query string.
When our mobile app user sends app-invite to fb user and he accepts it, the server should give a reward to the first one. So I need a way to verify whether the invite was sent.
var fb = new FacebookClient(APP_ID + "|" + SECRET_ID);
fb.AppId = APP_ID;
fb.AppSecret = SECRET_ID;
dynamic result = fb.Get(???);
I searched on GraphAPI docs and it seems that I need to retrieve users apprequests. How to do that from the server side and where to look at to perform such verification?
UPDATE
Ok, now I know that it's allowed to reward only for accepted invites. I can record who invites who in the db and give a reward only when a new invited user joins. But I still need a way to verify that these invites were actually sent.
UPDATE2
As the documentation states apprequests call from application returns all the requests sent from this application. So I think it would be enough for me to just check that there are any requests from this app:
dynamic result = fb.Get("/" + facebookId + "/apprequests");
IEnumerable data = result.data;
return data.Cast<object>().Count() != 0;
But I can't check it now. Can anyone confirm that if a user sends invite to app to another user this invite will be seen through apprequests from the application access token?
my code for this:
public static FacebookRequestData GetInviteHash()
{
string requestId = Request["request_ids"];
var accessToken = GetAccessToken(ConfigurationManager.AppSettings["FacebookAppId"], ConfigurationManager.AppSettings["FacebookSecret"]);
string response;
using (var webClient = new WebClient())
{
response = webClient.DownloadString(string.Format("https://graph.facebook.com/{0}?{1}", requestId, accessToken));
}
var javaScriptSerializer = new JavaScriptSerializer();
return javaScriptSerializer.Deserialize<FacebookRequestData>(javaScriptSerializer.Deserialize<FacebookRequestInfo>(response).data);
}
private static string GetAccessToken(string appId, string password)
{
using (var webClient = new WebClient())
{
return webClient.DownloadString(string.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&client_secret={1}&grant_type=client_credentials", appId, password));
}
}
private class FacebookRequestInfo
{
public string data { get; set; }
}
FacebookRequestData - my custom class with structure of fields that I posted to fb earlier
Done it:
public static bool CheckInvite(string fromId, string toId)
{
var fb = new FacebookClient(APP_ID + "|" + SECRET_ID);
fb.AppId = APP_ID;
fb.AppSecret = SECRET_ID;
dynamic result = fb.Get(string.Format("/{0}/apprequests", toId));
foreach (var el in result.data)
if ((string)el.from.id == fromId)
{
DateTime dateTime = DateTime.Parse((string)el.created_time, CultureInfo.InvariantCulture);
if ((DateTime.Now - dateTime).TotalMinutes < 15)
{
return true;
}
}
return false;
}
I'm trying to set up a WCF service protected by ADFS. I'm currently able to request a token and send it with the request using WIF and Thinktecture IdentityModel 4.5 with the following code:
static SecurityToken GetToken()
{
var factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
"https://fs2.server2012.local/adfs/services/trust/13/usernamemixed")
{
TrustVersion = TrustVersion.WSTrust13
};
if (factory.Credentials != null)
{
factory.Credentials.UserName.UserName = #"username";
factory.Credentials.UserName.Password = "password";
}
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Symmetric,
AppliesTo = new EndpointReference(
"https://wcfservicecertificate/wcfservice/Service.svc/wstrust"),
};
var channel = factory.CreateChannel();
RequestSecurityTokenResponse rstr;
return channel.Issue(rst, out rstr);
}
With this I can call the WCF service by using ChannelFactory.CreateChannelWithIssuedToken:
var factory = new ChannelFactory<IService>(binding,
new EndpointAddress("https://wcfservicecertificate/wcfservice/Service.svc/wstrust"));
if (factory.Credentials != null)
{
factory.Credentials.SupportInteractive = false;
factory.Credentials.UseIdentityConfiguration = true;
}
var proxy = factory.CreateChannelWithIssuedToken(GetToken());
var result= proxy.GetData(2);
This works as expected but can only be used on (mobile) windows platforms. I would also like to be able to use the same principle on iOS and Android. Using this article I was able to request a security token from ADFS using the following code:
const string soapMessage =
#"<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope""
xmlns:a=""http://www.w3.org/2005/08/addressing""
xmlns:u=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"">
<s:Header>
<a:Action s:mustUnderstand=""1"">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action>
<a:To s:mustUnderstand=""1"">https://fs2.server2012.local/adfs/services/trust/13/UsernameMixed</a:To>
<o:Security s:mustUnderstand=""1"" xmlns:o=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"">
<o:UsernameToken u:Id=""uuid-6a13a244-dac6-42c1-84c5-cbb345b0c4c4-1"">
<o:Username>username</o:Username>
<o:Password Type=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"">password</o:Password>
</o:UsernameToken>
</o:Security>
</s:Header>
<s:Body>
<trust:RequestSecurityToken xmlns:trust=""http://docs.oasis-open.org/ws-sx/ws-trust/200512"">
<wsp:AppliesTo xmlns:wsp=""http://schemas.xmlsoap.org/ws/2004/09/policy"">
<a:EndpointReference>
<a:Address>https://wcfservicecertificate/wcfservice/Service.svc/wstrust</a:Address>
</a:EndpointReference>
</wsp:AppliesTo>
<trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</trust:KeyType>
<trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
<trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType>
</trust:RequestSecurityToken>
</s:Body>
</s:Envelope>";
var webClient = new WebClient();
webClient.Headers.Add("Content-Type", "application/soap+xml; charset=utf-8");
var result = webClient.UploadString(
address: "https://fs2.server2012.local/adfs/services/trust/13/UsernameMixed",
method: "POST",
data: soapMessage);
This results in a SAML2.0 token which I would like to send in a request to our WCF service in order to authenticate. There are various sources (including the article mentioned earlier) which state that this should be possible but I've yet to find a solution.
Any help would be appreciated.
You can use one of hybrid solutions which use SAML with OAuth or other authorization technologies. This is more secure against phising techniques. For SAML only approach, you can refer to following link: How to pass security tokenfrom one wcf service to another wcf service. It is said that you need to enable saveBootstrapTokens property on webconfig.
This link can be useful too: Availability of Bootstrap Tokens
This can easily be done without using WIF. Lets completely avoid WIF and the .Net framework and do it in Java for illustration purposes. First make a call to the Security Token Service using the template approach like you have done. You then need to extract the SAML from the response, Base64 encode it and stuff it in the Autorization header of the subsequent request to your protected WCF service. You may also need to do the same with a ProofKey if you are coding for Non-Repudiation. Also I'm only showing authentication using username/password for brevity as Certificate Authentication involves much more work - you have to hash (SHA1 )part of the message then encrypt the hash with the private key of the cert and then add this as a xml element to the original message etc...
Here is the java helper code:
import java.io.*;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.Instant;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HttpsURLConnection;
public class SecurityService {
private String _username;
private String _password;
private String _stsUrl;
private String _samlAssertion;
private String _samlEncoded;
private String _binarySecret;
private String _workingDirectory;
private String _platformUrl;
private String _soapBody;
private Integer _responseCode;
private Integer _plaformResponseCode;
private String _response;
private String _platformResponse;
private String _xproofSignature;
private Map<String, String> _headerDictionary;
public void setUsername(String username) {
this._username = username;
}
public void setPassword(String password) {
this._password = password;
}
public void setStsUrl(String stsUrl) {
this._stsUrl = stsUrl;
}
public String getStsUrl() {
return _stsUrl;
}
public void setplatformUrl(String platformUrl) {
this._platformUrl = platformUrl;
}
public String getSamlAssertion() {
return _samlAssertion;
}
public String getSamlEncoded() {
return _samlEncoded;
}
public String getSoapBody() {
return _soapBody;
}
public Integer getResponseCode() {
return _responseCode;
}
public Integer getPlatformResponseCode() {
return _plaformResponseCode;
}
public String getResponse() {
return _response;
}
public String getPlatformResponse() {
return _platformResponse;
}
public String getXProofSignature() {
return _xproofSignature;
}
public String getBinarySecret() {
return _binarySecret;
}
public String gePlatFormUrl() {
return _platformUrl;
}
public void setHeaderDictionary(Map<String, String> headerDictionary){
this._headerDictionary = headerDictionary;
}
public Map<String, String> getHeaderDictionary(){
return _headerDictionary;
}
public SecurityService() throws Exception {
}
public SecurityService(Boolean useConfig) throws Exception {
if (useConfig) {
this._workingDirectory = System.getProperty("user.dir") + "\\app.config";
this.getProperties();
}
}
public void sendAuthenticatedGet() throws Exception {
URL obj = new URL(_platformUrl);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
// optional default is GET
con.setRequestMethod("GET");
// Add request header
con.setRequestProperty("Authorization", "Saml " + _samlEncoded);
con.setRequestProperty("X-ProofSignature", _xproofSignature);
_plaformResponseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
_platformResponse = response.toString();
}
public void sendAuthenticatedPost(String body) throws Exception {
URL obj = new URL(_platformUrl);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
//add request header
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/json");
// Add request header
con.setRequestProperty("Authorization", "Saml " + _samlEncoded);
con.setRequestProperty("X-ProofSignature", _xproofSignature);
// Add Azure Subscription Key using generic Add Headers method
if (_headerDictionary != null) {
for (String key : _headerDictionary.keySet()) {
con.setRequestProperty(key, _headerDictionary.get(key));
}
}
_soapBody = body;
// Send post request
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
//wr.writeBytes(urlParameters);
wr.writeBytes(_soapBody);
wr.flush();
wr.close();
_responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
_response = response.toString();
}
// HTTP POST request
public void sendPostToSts() throws Exception {
URL obj = new URL(_stsUrl);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
//add request header
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/soap+xml");
String body = getTemplateCertificate();
_soapBody = (((body.replace("[Created]", Instant.now().toString())).replace("[Expires]", Instant.now()
.plusSeconds(300).toString())).replace("[username]", _username)).replace("[password]", _password).replace("[stsUrl]", _stsUrl);
// Send post request
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
//wr.writeBytes(urlParameters);
wr.writeBytes(_soapBody);
wr.flush();
wr.close();
_responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
_response = response.toString();
// Get Binary Secret
// <trust:BinarySecret></trust:BinarySecret>
final Pattern patternBinarySecret = Pattern.compile("<trust:BinarySecret>(.+?)</trust:BinarySecret>");
final Matcher matcherBinarySecret = patternBinarySecret.matcher(response.toString());
matcherBinarySecret.find();
_binarySecret = matcherBinarySecret.group(1);
// Get the SAML Assertion
final Pattern patternEncryptedAssertion = Pattern.compile("<trust:RequestedSecurityToken>(.+?)</trust:RequestedSecurityToken>");
final Matcher matcherEncryptedAssertion = patternEncryptedAssertion.matcher(response.toString());
matcherEncryptedAssertion.find();
_samlAssertion = matcherEncryptedAssertion.group(1);
byte[] proofKeyBytes = _binarySecret.getBytes("UTF-8");
String encoded = Base64.getEncoder().encodeToString(proofKeyBytes);
byte[] decoded = Base64.getDecoder().decode(encoded);
// SAML Stuff - Works beautifully
byte[] samlBytes = _samlAssertion.getBytes("UTF-8");
_samlEncoded = Base64.getEncoder().encodeToString(samlBytes);
_xproofSignature = this.encode(_samlAssertion, _binarySecret);
}
private static String readFile( String file ) throws IOException {
BufferedReader reader = new BufferedReader( new FileReader(file));
String line = null;
StringBuilder stringBuilder = new StringBuilder();
String ls = System.getProperty("line.separator");
try {
while( ( line = reader.readLine() ) != null ) {
stringBuilder.append( line );
stringBuilder.append( ls );
}
return stringBuilder.toString();
} finally {
reader.close();
}
}
// Embedded WS-Trust template for username/password RST
private static String getTemplate () {
return "<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:a=\"http://www.w3.org/2005/08/addressing\" xmlns:u= \"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"><s:Header><a:Action s:mustUnderstand= \"1\">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action><a:MessageID>urn:uuid:cfea5555-248c-46c3-9b4d- 54936b7f815c</a:MessageID><a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo><a:To s:mustUnderstand=\"1\">[stsUrl]</a:To><o:Security s:mustUnderstand=\"1\" xmlns:o=\"http://docs.oasis- open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\"><u:Timestamp u:Id=\"_0\"><u:Created>[Created] </u:Created><u:Expires>[Expires]</u:Expires></u:Timestamp><o:UsernameToken u:Id=\"uuid-e273c018-1da7-466e-8671-86f6bfe7ce3c- 17\"><o:Username>[username]</o:Username><o:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username- token-profile-1.0#PasswordText\">[password] </o:Password></o:UsernameToken></o:Security></s:Header><s:Body><trust:RequestSecurityToken xmlns:trust=\"http://docs.oasis- open.org/ws-sx/ws-trust/200512\"><wsp:AppliesTo xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy \"><wsa:EndpointReference xmlns:wsa=\"http://www.w3.org/2005/08/addressing \"><wsa:Address>https://mbplatform/</wsa:Address></wsa:EndpointReference></wsp:AppliesTo><trust:RequestType>http://docs.oasis- open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType><trust:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token- profile-1.1#SAMLV2.0</trust:TokenType></trust:RequestSecurityToken></s:Body></s:Envelope>";
}
private String encode(String key, String data) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
return Base64.getEncoder().encodeToString(sha256_HMAC.doFinal(data.getBytes("UTF-8")));
}
private void getProperties() throws Exception {
Properties prop = new Properties();
String fileName = _workingDirectory;
InputStream is = new FileInputStream(fileName);
prop.load(is);
_username = prop.getProperty("app.username");
_password = prop.getProperty("app.password");
_platformUrl = prop.getProperty("app.platformUrl");
_stsUrl = prop.getProperty("app.stsUrl");
}
}
and here is example usage:
SecurityService mbss = new SecurityService(true);
mbss.sendPostToSts();
System.out.println("CONTACTING AZURE SECURITY TOKEN SERVICE");
System.out.println("\nSending 'POST' request to URL : " + mbss.getStsUrl());
System.out.println("\nPost parameters : \n" + mbss.getSoapBody());
System.out.println("\nResponse Code : " + mbss.getResponseCode());
System.out.println("\nHERE IS THE SAML RESPONSE\n");
System.out.println(mbss.getResponse());
System.out.println("\nHERE IS THE BINARY SECRET\n");
System.out.println(mbss.getBinarySecret());
System.out.println("\nHERE IS THE SAML ASSERTION\n");
System.out.println(mbss.getSamlAssertion());
System.out.println("\nHERE IS THE ENCODED SAML ASSERTION\n");
System.out.println(mbss.getSamlEncoded());
System.out.println("\nHERE IS THE X-PROOF SIGNATURE\n");
System.out.println(mbss.getXProofSignature());
System.out.println("\nNOW CONTACTING WCF SERVICES WITH SECURITY HEADER\n");
mbss.sendAuthenticatedGet();
System.out.println("\nSending 'GET' request to URL : " + mbss.gePlatFormUrl());
System.out.println("Response Code : " + mbss.getPlatformResponseCode());
System.out.println("\nHERE ARE THE RESULTS FOLKS...ENJOY\n");
System.out.println(mbss.getPlatformResponse());
I am having an issue with OAuth and Facebook. I am using MVC4 standard OAuth login. I am not having the issue locally but on the server this is proving to be a problem.
If I paste the following URL into the browser it works OK:
http://localhost:46260/Account/ExternalLoginCallback?ReturnUrl=%2FDashboard&__provider__=FacebookPro&__sid__=1234somesid456 // this is autogenerated
When I change the URL for the app in facebook to the current domain and paste this url in, I get re-directed to the Unsuccessful login page:
http://freersvp.mytakeawaysite.com:80/Account/ExternalLoginCallback?ReturnUrl=%2FDashboard&__provider__=Facebook+Pro&__sid__=1234someid456 // note this is autogenerated
N.B The above two url's are the redirect uri
The below URL is what is requested and is causing the exception:
URL
https://graph.facebook.com/oauth/access_token?client_id=52*********37&redirect_uri=http%3a%2f%2ffreersvp.mytakeawaysite.com%3a80%2fAccount%2fExternalLoginCallback%3fReturnUrl%3d%252FDashboard%26__provider__%3dFacebook%2bPro%26__sid__%3d3c92eb7e84304afc931ef0ea7b62f56a&client_secret=2123***********4256&code=AQAQIJsj-ondldllVYKdpxJaZouqrlg9sjTcfUxyWhAw8MXbD2DvsOSujg2m7E3s3cvNusCI0ZZoJAuGgu_FLkPyjYMQAkTWDVyHTcAoJD-tezyXgn0vhoFzX3FmuRBHYpyJEM-dk0KgF5ugsTHo9yGjBjrcfMDUGu9IxkKQ36k3gMrwocM1_l5t342Q2kIOHdt8pPcyrs--NzgNyZv48vSq7jkZwuQ95xRjUHG5J-ptcgq0l2BlqjzHDDuvIFH23lpMWHzzqdejdj5ejukz7t_Fnhx-mrpVdcRYhP3JeZ2UOTjAyKQmUB3rInooECcjq4c
Exception
{
"error": {
"message": "Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request",
"type": "OAuthException",
"code": 100
}
}
The string token does come back with null in the GetUserData function in the below code:
I am using the FacebookScopedClient:
public class FacebookScopedClient : IAuthenticationClient
{
private string appId;
private string appSecret;
private string scope;
private const string baseUrl = "https://www.facebook.com/dialog/oauth?client_id=";
public const string graphApiToken = "https://graph.facebook.com/oauth/access_token?";
public const string graphApiMe = "https://graph.facebook.com/me?";
private static string GetHTML(string URL)
{
string connectionString = URL;
try
{
System.Net.HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(connectionString);
myRequest.Credentials = CredentialCache.DefaultCredentials;
//// Get the response
WebResponse webResponse = myRequest.GetResponse();
Stream respStream = webResponse.GetResponseStream();
////
StreamReader ioStream = new StreamReader(respStream);
string pageContent = ioStream.ReadToEnd();
//// Close streams
ioStream.Close();
respStream.Close();
return pageContent;
}
catch(Exception ex)
{
}
return null;
}
private IDictionary<string, string> GetUserData(string accessCode, string redirectURI)
{
SessionControl ctl = new SessionControl();
ctl.SaveParam("redirecturi", redirectURI, -3);
ctl.Dispose();
string token = GetHTML(graphApiToken + "client_id=" + appId + "&redirect_uri=" + HttpUtility.UrlEncode(redirectURI) + "&client_secret=" + appSecret + "&code=" + accessCode);
if(token == null || token == "")
{
return null;
}
string access_token = token.Substring(token.IndexOf("access_token="), token.IndexOf("&"));
string data = GetHTML(graphApiMe + "fields=id,name,email,username,gender,link&" + access_token);
try
{
}
catch { }
// this dictionary must contains
Dictionary<string, string> userData = JsonConvert.DeserializeObject<Dictionary<string, string>>(data);
userData.Add("accesstoken", access_token);
try
{
userData.Add("id", userData["id"]);
}
catch { }
return userData;
}
public FacebookScopedClient(string appId, string appSecret, string scope)
{
this.appId = appId;
this.appSecret = appSecret;
this.scope = scope;
}
public string ProviderName
{
get { return "FacebookPro"; }
}
public void RequestAuthentication(System.Web.HttpContextBase context, Uri returnUrl)
{
string url = baseUrl + appId + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString()) + "&scope=" + scope;
context.Response.Redirect(url);
}
public AuthenticationResult VerifyAuthentication(System.Web.HttpContextBase context)
{
string code = context.Request.QueryString["code"];
string rawUrl = context.Request.Url.OriginalString;
//From this we need to remove code portion
rawUrl = Regex.Replace(rawUrl, "&code=[^&]*", "");
IDictionary<string, string> userData = GetUserData(code, rawUrl);
if(userData == null)
return new AuthenticationResult(false, ProviderName, null, null, null);
string id = userData["id"];
string username = userData["email"];
if(username == null || username == "")
{
username = userData["username"];
}
//userData.Remove("id");
userData.Remove("username");
AuthenticationResult result = new AuthenticationResult(true, ProviderName, id, username, userData);
return result;
}
}
after running your posted url that's causing the error through a url decoder the issue lies in for some reason your url encoding the entire query string and not just the url.
you will notice in that url a bunch of %26 items those are url encoded & and that's what is throwing your error. the Facebook parser is seeing %26 instead of & and treating it as one single parameter.
the & separates url query string parameters when sending to a page. Without the full code I can't tell you where to look but some where in your code your completely encoding the entire query string and need to find that piece of code and only encode the embedded urls.
ok after reading over things maybe try this theory.
I think your code is receiving this stuff from Facebook, url encoded, and then your system is re-encoding it. try taking anything received and first url decode it, manipulate it and then re-encode things as needed.
hope this helps
Try it with sandbox mode off within facebook app.
Noticing your URL's query string, I found an answer from Stackoverflow. Please see if it solves your issue:
https://stackoverflow.com/a/16699058/2005136
Steve S posted as a response:
"In our case, we were doing something unusual (so this might not be relevant to your case). Our redirect_uri was a URL with another URL embedded as an encoded path element. The URL-within-a-URL, doubly-encoded when passed to FB, had started causing problems with the Facebook API servers.
We resolved this by changing the encoding of the nested URL to a long hex number rather than % encoding, so all Facebook servers see is a simple redirect_uri containing some hex within the path, unaffected by normal URL encoding/decoding."