400 bad request when querying microsoft graph with http post - vb.net

I've been doing some testing with Microsoft Graph and I seem to have hit a brick wall; Wondering if anyone can give me a steer in the right direction.
The following code is from my test app (vb)...
Imports System.Net
Imports System.Text
Imports System.IO
Imports Newtonsoft.Json.Linq
Class MainWindow
Public Shared graph_url As String = "https://graph.microsoft.com/v1.0/"
Public Shared br As String = ControlChars.NewLine
Dim myscope As String = "https://graph.microsoft.com/.default"
Dim mysecret As String = "zzx...BX-"
Dim mytenantid As String = "7aa6d...d409199"
Dim myclientid As String = "4e37...5a59"
Dim myuri As String = "https://login.microsoftonline.com/" & mytenantid & "/oauth2/v2.0/token"
Dim mytoken As String = ""
Public Function HTTP_Post(ByVal url As String, ByVal postdata As String)
Try
Dim encoding As New UTF8Encoding
Dim postReq As HttpWebRequest = DirectCast(WebRequest.Create(url), HttpWebRequest)
postReq.Headers.Add("Authorization", "Bearer " & mytoken)
postReq.Method = "POST"
postReq.PreAuthenticate = True
Dim postreqstream As Stream = postReq.GetRequestStream()
If Not postdata = Nothing Then
Dim byteData As Byte() = encoding.GetBytes(postdata)
postreqstream.Write(byteData, 0, byteData.Length)
End If
postreqstream.Close()
request_header.Text = postReq.Headers.ToString
Dim postresponse As HttpWebResponse = DirectCast(postReq.GetResponse(), HttpWebResponse)
Dim postreqreader As New StreamReader(postresponse.GetResponseStream())
Dim response As String = postreqreader.ReadToEnd
Return (response)
Catch ex As Exception
user_results.Text = ex.Message.ToString
End Try
End Function
Public Function GetNewToken()
Console.WriteLine(myuri)
Dim post_data As String = "client_id=" & myclientid & "&client_secret=" & mysecret & "&scope=" & myscope & "&grant_type=client_credentials"
Dim token As String = HTTP_Post(myuri, post_data)
get_result.Text = JObject.Parse(token).SelectToken("access_token")
mytoken = JObject.Parse(token).SelectToken("access_token")
End Function
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
GetNewToken()
End Sub
Private Sub usrget_Copy_Click(sender As Object, e As RoutedEventArgs) Handles usrget_Copy.Click
Dim url As String = "https://graph.microsoft.com/v1.0/users/*{myUPN}*"
Dim post_data As String = Nothing
Dim return_data As String = HTTP_Post(url, post_data)
req_url.Text = url
End Sub
End Class
The GetNewToken() function works fine and I retrive a valid token without an issue.
When i try and use that token to query a user, i get 400 Bad request - no additional info as such; just that.
I've examined the headers of my POST request and tried it several different ways, but cannot seem to overcome this; As far as i can tell my request is formatted as specified in the documentation for Microsoft Graph.
Have also googled the hell out of this to see if there was something obvious or simple I have overlooked; I've seen a few posts on this topic where people suggested setting the Authorization header before anything else - I tried that and it made no difference.
A few people also suggected setting the Accept to 'application/json'; I also tried that and it made no difference.
I've outputted some of the details to the gui and grabbed a screenshot so you can see what I'm seeing...
Interestingly, If i try the 'Query users' before i grab a token, I get a 401 unauthorized which would suggest that the request itself is working correctly.
As i mentioned, this is a testing app whilst I get some functionality working (some data obscured for obvious reasons); I'm not concerned about the tidyness of code or anything like that at this point.
If anyone is able to help it would be very much appriciated.
Thanks in advance.

Related

HTTP POST .NET aspx.vb doesn't work using Class Library, works with Windows Forms Apps

I the code below works fine with using VS 2019 and selecting Windows Forms Applications from the project properties. When I try to use the same code though in a "Class Library" for Web Forms, it doesn't work.
Target framework is .NET Framework 4.7.2 (i have to stay within .NET 4.0 for other references)
The host server requires me to login (username/password) via a pop-up when URL is entered on a web browser. This is why you see below request.Credentials being used. As far as I know, the host system is using TLS 1.2 as well.
The error shows when it hits
Dim dataStream As Stream = request.GetRequestStream() 'Get the request stream.
But the HTTP/S POST also doesn't work, but doesn't error out either.
Could it be a bug with built in IIS Express (Google Chrome)? I tried IE and Edge, same thing.
Imports System.IO
Imports System.Net
Imports System.Text
Public Class POST_ASN
Inherits System.Web.UI.Page
'Protected Sub Page_Load(ByVal sender As Object, ByVal As Examples.System.EventArgs) Handles Me.Load
'End Sub
Public Shared Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim url As String = "https://myurl.somehost.com/invoke/HTTPConnector.Mailbox/post"
Dim username As String = "user123"
Dim password As String = "pass123"
Dim networkCredential As New NetworkCredential(username, password)
Dim postData As String = ""
' Create a request using a URL that can receive a post.
Dim Request As HttpWebRequest = CType(WebRequest.Create(url), HttpWebRequest)
Request.Method = "POST"
request.PreAuthenticate = True
request.Credentials = networkCredential
' Create POST data and convert it to a byte array.
postData = "EDI data string here ASCII"
Dim byteArray As Byte() = Encoding.UTF8.GetBytes(postData)
request.ContentType = "application/octet-stream" ' Set the ContentType property of the WebRequest.
request.ContentLength = byteArray.Length ' Set the ContentLength property of the WebRequest.
'Get the request stream.
Dim dataStream As Stream = request.GetRequestStream()
'Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length)
' Close the Stream object
dataStream.Close()
' Assign the response object of 'WebRequest' to a 'WebResponse' variable.
Dim response As WebResponse = request.GetResponse()
' Get the stream containing content returned by the server.
Dim trackingID As String
Using dataStream1 As Stream = response.GetResponseStream()
'Open the stream using a StreamReader for easy access.
Dim reader As New StreamReader(dataStream1)
' Read the content.
Dim responseFromServer As String = reader.ReadToEnd()
trackingID = Mid(responseFromServer, 65, 10)
' Display the content.
MsgBox("Tracking ID: " & trackingID)
End Using
' Clean up the response.
response.Close()
End Sub
End Class
I also read posts about setting ServicePointManager.SecuirtyProtocol, none of these worked, and i tried difference scenarios. According to MS, using .NET 4.7, TLS1.2 is already invoked.
'ServicePointManager.Expect100Continue = True
'ServicePointManager.SecurityProtocol = CType(3072, SecurityProtocolType)
'ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3
'ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
'ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls 'Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12
The purpose of all this was to migrate off my Excel VBA solution. This code below works fine, so if anyone knows how to take this and convert it to .NET Framework Class Library VB.aspx web page, please help.
'Create HTTP connection
Set xmlhttp = CreateObject("MSXML2.XMLHTTP.6.0")
xmlhttp.Open "POST", strURL, False, UploadUser, UploadPass 'Sync request
xmlhttp.Send sData
strValue = xmlhttp.responsetext
Set xmlhttp = Nothing
trackingID = Mid(strValue, 65, 10)

VB.NET - Salesforce POST Request returns 400 Bad Request Error

NOTE: I've never written vb.net code before this. I've googled for a solution but did not find anything that worked.
I'm trying to get access token from Salesforce. Below code worked just yesterday. And I have no idea why it is not working today. I've tried adding content-type as application/x-www-form-urlencoded but it did not work either. When I use curl I'm able to get access token. Also I'm able to get access token using advanced rest client in google chrome. Any ideas why it is returning 400 Bad Request unknown error retry your request?
Imports System.Collections.Specialized
Imports System.Net
Imports System.Text
Module Module1
Sub Main()
Dim clientId As String = "clientId"
Dim clientSecret As String = "clientSecret"
Dim redirectUri As String = "https://test.salesforce.com"
Dim environment As String = "https://test.salesforce.com"
Dim tokenUrl As String = ""
Dim username As String = "username#salesforce.com"
Dim password As String = "passwordtoken"
Dim accessToken As String = ""
Dim instanceUrl As String = ""
Console.WriteLine("Getting a token")
tokenUrl = environment + "/services/oauth2/token"
Dim request As WebRequest = WebRequest.Create(tokenUrl)
Dim values As NameValueCollection = New NameValueCollection()
values.Add("grant_type", "password")
values.Add("client_id", clientId)
values.Add("client_secret", clientSecret)
values.Add("redirect_uri", redirectUri)
values.Add("username", username)
values.Add("password", password)
request.Method = "POST"
Try
Dim client = New WebClient()
Dim responseBytes As Byte() = client.UploadValues(tokenUrl, "POST", values)
Dim response As String = Encoding.UTF8.GetString(responseBytes)
Console.WriteLine(response)
Console.ReadKey()
Catch ex As Exception
Console.WriteLine(ex.Message)
Console.WriteLine("Press any key to close")
Console.ReadKey()
End Try
End Sub
End Module
Well, appearently problem was about TLS version mismatch. All Salesforce sandboxes refuse TLS 1.0 connections. Our vb.net test code was using TLS 1.0 thus returning an error. It would be great if Salesforce would return better error code.
All I needed to do was add a line of code on top of the code block:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11

Trouble Authenticating with WP remote login request

Okay so I was going to post this on the last 3 errors I got, but I fixed those all(thankfully). I no longer get any kind of cookie blocked message, however now I get a Error logging in whether I'm putting in the correct password or an invalid one. I think its either
A. a cookie storage error.
B. or a problem with redirection.
Imports System.Text
Imports System.Net
Imports System.IO
Public Class Form1
Dim logincookie As CookieContainer
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim postData As String = "log=" & TextBox1.Text & "&pwd=" & TextBox2.Text & "wp- submit=Log+In&redirect_to=""http://csvlife.com/wp-admin/" & "&wordpress_test_cookie=1"
Dim tempcookies As New CookieContainer()
Dim encoding As New UTF8Encoding
Dim byteData As Byte() = encoding.GetBytes(postData)
Dim postreq As HttpWebRequest = DirectCast(HttpWebRequest.Create("http://csvlife.com/wp-login.php"), HttpWebRequest)
postreq.Method = "POST"
postreq.KeepAlive = True
postreq.AllowAutoRedirect = True
postreq.CookieContainer = tempcookies
postreq.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b6pre) Gecko/20100903 Firefox/4.0b6pre"
postreq.ContentType = "application/x-www-form-urlencoded"
postreq.Referer = "http://csvlife.com/wp-login.php"
postreq.ContentLength = byteData.Length
Dim postreqstream As Stream = postreq.GetRequestStream()
postreqstream.Write(byteData, 0, byteData.Length)
postreqstream.Close()
Dim postresponse As HttpWebResponse
postresponse = DirectCast(postreq.GetResponse, HttpWebResponse)
tempcookies.Add(postresponse.Cookies)
logincookie = tempcookies
Dim postreqreader As New StreamReader(postresponse.GetResponseStream())
Dim thepage As String = postreqreader.ReadToEnd
If thepage.Contains("ERROR") Then
MsgBox("Error logging in!")
Else
MsgBox("Lets Start Blogging!")
End If
End Sub
End Class
I have my fiddler open and I've logged into the page and noticed that when I login regularly from by regular browser
fiddler will show this:
then the results come in and it looks like this:
Clarification: The pictures above is what the web traffic info looks like when I login from any basic browser on my computer
Here is what it looks like what I login from the program:
Always an error.
And the request number is just 200 no 302 before or after.
However when I try through my program the req number always remains 200 which is post. Its like it never gets to redirect and I don't know why. Notes: This is my website and this not for any kind of malware or whatever. Its just for blog automation. If there was anything else I could find on this matter I would. At this point I have no other option. Thank you kindly for your help and consideration.
In line 9:
Dim postData As String = "log=" & TextBox1.Text & "&pwd=" & TextBox2.Text & "wp- submit=Log+In&redirect_to=""http://csvlife.com/wp-admin/" & "&wordpress_test_cookie=1"
The parameters to be sent with the post need to be separated with an ampersand, as written the password parameter has "wp- submit=Log+In&redirect_to=http://csvlife.com/wp-admin/" appended to it.
Assuming wp is a parameter:
Dim postData As String = "log=" & TextBox1.Text & "&pwd=" & TextBox2.Text & "&wp- submit=Log+In&redirect_to=""http://csvlife.com/wp-admin/" & "&wordpress_test_cookie=1"

Creating webrequest POST for Twitter API using VB.NET

There are quite a few Twitter API related posts, but none seem to answer my questions directly.
I know how to send an HttpWebRequest as POST.
I am fairly sure I need to send the webrequest to: "https://api.twitter.com/1/statuses/update.json" (not totally clear)
I know there are many libraries out there that all you have to do is pass your consumer keys and token keys. However, I need to create some very short code, in a function, that simple posts a hard coded string to Twitter. When I get this working that hard coded string will be replaced by variable.
I've no need to status updates or any kind of information from Twitter. Just POST "Hello World!" to start with, and I can go from there.
I am forced to use VB.NET. I am using Visual Studio Web Developer 2010.
Now, that all said, I have looked at Nikolas Tarzia's VB.NET port of C-Sharp code here:
http://oauth.googlecode.com/svn/code/vbnet/oAuth.vb
I can see roughly what the functions do by looking at them, but have no idea which ones I need to call to create a webresponse and send to Twitter! Also I believe this code contains more than I need. If I just want to create a POST, then likely I only need to hash function and the nonce function and my tokens and keys. Is that right? If so, could someone please help me narrow this down? In the process helping me understand a bit better what properly formed webrequest needs to be sent to Twitter to make a quick Tweet?
Thanks,
Will
PS - I finally put together some code, based on looking at OAuth documentation, a neat little code example on using POST request in VB, and the Twitter Developer area OAuth tool to generate some Base String for the request. Unfortunately while it compiles and runs okay, I am not getting a tweet. Could someone have a look at the code and see if they can spot any glaring issues? Obviously I replaced my tokens and consumer keys with "xxxxx". All I want for Christmas is to run this code and make a quick Tweet on my Twitter account! ;)
Public Shared Function Tweet(strText As String) As Boolean
Dim boolResult As Boolean = False
Dim urlAddress As Uri = New Uri("https://api.twitter.com/1/statuses/update.json")
Dim strData As StringBuilder
Dim byteData() As Byte
Dim postStream As Stream = Nothing
Dim strConsumerKey As String = "xxxxxx"
Dim strConsumerSecret As String = "xxxxxx"
Dim strAccessToken As String = "xxxxxx"
Dim strAccessTokenSecret As String = "xxxxxx"
Dim objRequest As HttpWebRequest
Dim objResponse As HttpWebResponse = Nothing
Dim objReader As StreamReader
Dim objHeader As HttpRequestHeader = HttpRequestHeader.Authorization
Try
objRequest = DirectCast(WebRequest.Create(urlAddress), HttpWebRequest)
objRequest.Method = "POST"
objRequest.ContentType = "application/x-www-form-urlencoded"
strData = New StringBuilder()
strData.Append("&Hello_World%2521%3D%26oauth_consumer_key%3D" + strConsumerKey + "%26oauth_nonce%3Dda6bb8ce7e48547692f4854833afa680%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1329746260%26oauth_token%3D" + strAccessToken + "%26oauth_version%3D1.0")
objRequest.Headers.Add(objHeader, "Authorization: OAuth oauth_consumer_key=""xxxx"", oauth_nonce=""da6bb8ce7e48547692f4854833afa680"", oauth_signature=""xxxx"", oauth_signature_method=""HMAC-SHA1"", oauth_timestamp=""1329750426"", oauth_token=""xxxx"", oauth_version=""1.0""")
' Create a byte array of the data we want to send
byteData = UTF8Encoding.UTF8.GetBytes(strData.ToString())
' Set the content length in the request headers
objRequest.ContentLength = byteData.Length
Try
postStream = objRequest.GetRequestStream()
postStream.Write(byteData, 0, byteData.Length)
Finally
If Not postStream Is Nothing Then postStream.Close()
End Try
boolResult = True
Catch ex As Exception
boolResult = False
HttpContext.Current.Session.Add("Error", ex.ToString())
End Try
Try
' Get response
objResponse = DirectCast(objRequest.GetResponse(), HttpWebResponse)
' Get the response stream into a reader
objReader = New StreamReader(objResponse.GetResponseStream())
' Console application output
Console.WriteLine(objReader.ReadToEnd())
Finally
If Not objResponse Is Nothing Then objResponse.Close()
End Try
Return boolResult
End Function
I´ve made this class to post in twitter using API1.1.
It expects the oauth token, oauth token secret, oauth "consumer" key (this means API key) and oauth consumer secret (this means API secret) in the constructor. If you want to post in your own account, the four values will be in the API keys tab of your application in https://apps.twitter.com/. If you want to post on your visitors account you'll have to create some extra code to redirect them to twitter for login and get the access token.
Imports Microsoft.VisualBasic
Imports System.Collections.Generic
Imports System.Linq
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Text
Imports System.Security.Cryptography
Imports System.Net
Imports System.IO
Public Class SBTwitter
Private oauth_token As String
Private oauth_token_secret As String
Private oauth_consumer_key As String
Private oauth_consumer_secret As String
Public Sub New(ByVal APIKey As String, ByVal APISecret As String, ByVal oauthToken As String, ByVal oauthTokenSecret As String)
oauth_token = oauthToken
oauth_token_secret = oauthTokenSecret
oauth_consumer_key = APIKey
oauth_consumer_secret = APISecret
End Sub
Public Function PostInTwitter(ByVal post As String) As String
Try
Dim oauth_version = "1.0"
Dim oauth_signature_method = "HMAC-SHA1"
Dim oauth_nonce = Convert.ToBase64String(New ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()))
Dim timeSpan = DateTime.UtcNow - New DateTime(1970, 1, 1, 0, 0, 0, _
0, DateTimeKind.Utc)
Dim oauth_timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString()
Dim resource_url = "https://api.twitter.com/1.1/statuses/update.json"
Dim status = post
Dim baseFormat = "oauth_consumer_key={0}&oauth_nonce={1}&oauth_signature_method={2}" & "&oauth_timestamp={3}&oauth_token={4}&oauth_version={5}&status={6}"
Dim baseString = String.Format(baseFormat, oauth_consumer_key, oauth_nonce, oauth_signature_method, oauth_timestamp, oauth_token, _
oauth_version, Uri.EscapeDataString(status))
baseString = String.Concat("POST&", Uri.EscapeDataString(resource_url), "&", Uri.EscapeDataString(baseString))
Dim compositeKey = String.Concat(Uri.EscapeDataString(oauth_consumer_secret), "&", Uri.EscapeDataString(oauth_token_secret))
Dim oauth_signature As String
Using hasher As New HMACSHA1(ASCIIEncoding.ASCII.GetBytes(compositeKey))
oauth_signature = Convert.ToBase64String(hasher.ComputeHash(ASCIIEncoding.ASCII.GetBytes(baseString)))
End Using
Dim headerFormat = "OAuth oauth_nonce=""{0}"", oauth_signature_method=""{1}"", " & "oauth_timestamp=""{2}"", oauth_consumer_key=""{3}"", " & "oauth_token=""{4}"", oauth_signature=""{5}"", " & "oauth_version=""{6}"""
Dim authHeader = String.Format(headerFormat, Uri.EscapeDataString(oauth_nonce), Uri.EscapeDataString(oauth_signature_method), Uri.EscapeDataString(oauth_timestamp), Uri.EscapeDataString(oauth_consumer_key), Uri.EscapeDataString(oauth_token), _
Uri.EscapeDataString(oauth_signature), Uri.EscapeDataString(oauth_version))
Dim postBody = "status=" & Uri.EscapeDataString(status)
ServicePointManager.Expect100Continue = False
Dim request As HttpWebRequest = DirectCast(WebRequest.Create(resource_url), HttpWebRequest)
request.Headers.Add("Authorization", authHeader)
request.Method = "POST"
request.ContentType = "application/x-www-form-urlencoded"
Using stream As Stream = request.GetRequestStream()
Dim content As Byte() = ASCIIEncoding.ASCII.GetBytes(postBody)
stream.Write(content, 0, content.Length)
End Using
Dim response As WebResponse = request.GetResponse()
Return response.ToString
Catch ex As Exception
Return ex.Message
End Try
End Function
End Class

How to post XML document to HTTP with VB.Net

I'm looking for help with posting my XML document to a url in VB.NET. Here's what I have so far ...
Public Shared xml As New System.Xml.XmlDocument()
Public Shared Sub Main()
Dim root As XmlElement
root = xml.CreateElement("root")
xml.AppendChild(root)
Dim username As XmlElement
username = xml.CreateElement("username")
username.InnerText = _username
root.AppendChild(username)
xml.Save(Console.Out)
Dim url = "https://mydomain.com"
Dim req As WebRequest = WebRequest.Create(url)
req.Method = "POST"
req.ContentType = "application/xml"
req.Headers.Add("Custom: API_Method")
Console.WriteLine(req.Headers.ToString())
This is where things go awry:
I want to post the xml, and then print the results to console.
Dim newStream As Stream = req.GetRequestStream()
xml.Save(newStream)
Dim response As WebResponse = req.GetResponse()
Console.WriteLine(response.ToString())
End Sub
This is essentially what I was after:
xml.Save(req.GetRequestStream())
If you don't want to take care about the length, it is also possible to use the WebClient.UploadData method.
I adapted your snippet slightly in this way.
Imports System.Xml
Imports System.Net
Imports System.IO
Public Module Module1
Public xml As New System.Xml.XmlDocument()
Public Sub Main()
Dim root As XmlElement
root = xml.CreateElement("root")
xml.AppendChild(root)
Dim username As XmlElement
username = xml.CreateElement("username")
username.InnerText = "user1"
root.AppendChild(username)
Dim url = "http://mydomain.com"
Dim client As New WebClient
client.Headers.Add("Content-Type", "application/xml")
client.Headers.Add("Custom: API_Method")
Dim sentXml As Byte() = System.Text.Encoding.ASCII.GetBytes(xml.OuterXml)
Dim response As Byte() = client.UploadData(url, "POST", sentXml)
Console.WriteLine(response.ToString())
End Sub
End Module