I'm trying to connect the business central with the sharepoint, I already did it in the postman, it worked fine, the GET and POST.
But now Im trying to do it on BC, the token is created but not working, I think it has some problem with the connection or the URL's.
codeunit 50100 "APISharePoint"
{
var
OAuth2: Codeunit OAuth2;
ClientIdTxt: Label '4d148348-137a-40e7-b20c-a458c2a03c65', Locked = true;
ClientSecret: Label 'Ai2pOhE7yeZ8WRxrwSrHdpVtNqJg51tg2X+s8CJDLy4=', Locked = true;
ResourceUrlTxt: Label 'https://crmbc384959.sharepoint.com', Locked = true;
OAuthAuthorityUrlTxt: Label 'https://login.microsoftonline.com/ec36749a-af47-4f04-892c-98666b6cac1b/oauth2/v2.0/token', Locked = true;
procedure GetAccessToken(): Text
var
PromptInteraction: Enum "Prompt Interaction";
AccessToken: Text;
AuthCodeError: Text;
RedirectURLTxt: Text;
begin
// OAuth2.GetDefaultRedirectURL(RedirectURLTxt);
RedirectURLTxt := 'https://localhost';
if OAuth2.AcquireTokenWithClientCredentials(ClientIdTxt, ClientSecret, OAuthAuthorityUrlTxt, RedirectURLTxt, ResourceURLTxt, AccessToken) then
exit(AccessToken)
else
exit('');
end;
procedure HttpGet(AccessToken: Text; Url: Text /*var JResponse: JsonObject*/): Boolean
var
Client: HttpClient;
Headers: HttpHeaders;
RequestMessage: HttpRequestMessage;
ResponseMessage: HttpResponseMessage;
RequestContent: HttpContent;
ResponseText: Text;
IsSucces: Boolean;
begin
Headers := Client.DefaultRequestHeaders();
Headers.Add('Authorization', StrSubstNo('Bearer %1', AccessToken));
Headers.Add('Accept', 'application/json;odata=verbose');
RequestMessage.Content.GetHeaders(Headers); //asd
Headers.Remove('Content-Type');
Headers.Add('Content-Type', 'application/json;odata=verbose');
RequestMessage.SetRequestUri(Url);
RequestMessage.Method := 'GET';
if Client.Send(RequestMessage, ResponseMessage) then
if ResponseMessage.IsSuccessStatusCode() then begin
if ResponseMessage.Content.ReadAs(ResponseText) then
IsSucces := true;
// end else
// ResponseMessage.Content.ReadAs(ResponseText);
// JResponse.ReadFrom(ResponseText);
exit(IsSucces);
end;
end;
Maybe your problem is the combination of GET with a request content.
As far as i know, the underlaying implementation of the HttpClient in .NET does not support GET with a request content. You can read more about it here: How to use HttpClient to send content in body of GET request?
Maybe you can try GET without setting the content-type on the content or use POST or PUT instead.
But you didn't supply a error message so this is just a guess.
Related
In my project, I use Inno to run a .sql script to create a database. I use a custom page to write SQL Server instance name user and password to run the script.
I would like to add the validation of the entered credentials. What's the best way?
Update:
I'm testing this approach
function ConnDBAndExecSql(istanza,utente,password:string):Boolean;
var
ADOConnection: Variant;
begin
Result := False;
try
// create the ADO connection object
ADOConnection := CreateOleObject('ADODB.Connection');
// build a connection string; for more information, search for ADO
// connection string on the Internet
ADOConnection.ConnectionString :=
'Provider=SQLOLEDB.1;' + // provider
'Data Source='+ istanza +';' + // server name
'Persist Security Info=True;' +
'User Id=' + utente + ';' + // user name
'Password='+ password + '; '; // password
// open the connection by the assigned ConnectionString
ADOConnection.Open;
Result := True;
//ADOConnection.Connected:=True;
except
Result:= False;
end;
end;
I am trying to do the modern authentication from azure ad with client certificate.
The process says.
Create an azure application.
Upload the certificate to azure application and get the thumbprint.
Generate the JWT token using that certificate(https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-certificate-credentials)
Then use that jwt-token to get the access-token.
To get the access-token, call an API (https://login.microsoftonline.com//oauth2/token)
The HTTP method is of type POST and post body data will be x-www-form-urlencoded
After doing all the steps when i try to get the token.
I get this error.
{
"error": "invalid_client",
"error_description": "AADSTS700023: Client assertion audience claim does not match Realm issuer. Review the documentation at https://learn.microsoft.com/azure/active-directory/develop/active-directory-certificate-credentials .\r\nTrace ID: 714b5009-b74d-46b5-bd0e-3bea76272a01\r\nCorrelation ID: 2cb703bb-f325-44b5-a669-605bc7a81ac0\r\nTimestamp: 2020-08-28 07:31:19Z",
"error_codes": [
700023
],
"timestamp": "2020-08-28 07:31:19Z",
"trace_id": "714b5009-b74d-46b5-bd0e-3bea76272a01",
"correlation_id": "2cb703bb-f325-44b5-a669-605bc7a81ac0"
}
I am generating the JWT token using go code and parsing the PFX file.
func getAuthJWTToken() (string, error) {
clientID := "**********************"
_tenantName := "******************"
pfxFilePath := `E:\abcd.pfx`
certPassword := `*********`
authToken := ""
pfxFile, err := os.Open(pfxFilePath)
if err != nil {
return authToken, err
}
pfxfileinfo, _ := pfxFile.Stat()
var size int64 = pfxfileinfo.Size()
pfxbytes := make([]byte, size)
buffer := bufio.NewReader(pfxFile)
_, err = buffer.Read(pfxbytes)
//PFX to PEM for computation of signature
var pembytes []byte
blocks, err := pkcs12.ToPEM(pfxbytes, certPassword)
for _, b := range blocks {
pembytes = append(pembytes, pem.EncodeToMemory(b)...)
}
//Decoding the certificate contents from pfxbytes
pk, cert, err := pkcs12.Decode(pfxbytes, certPassword)
if cert == nil {
fmt.Printf("Bye")
return authToken, nil
}
if pk == nil {
}
pfxFile.Close() // close file
notToBeUsedBefore := time.Now()
expirationTime := time.Now().Add(3000 * time.Minute)
URL := fmt.Sprintf("https://login.microsoftonline.com/%s/oauth2/token", _tenantName)
id := guid.New()
claims := &claims{
StandardClaims: jwt.StandardClaims{
// In JWT, the expiry time is expressed as unix milliseconds
ExpiresAt: expirationTime.Unix(),
Audience: URL,
Issuer: clientID, // consumer key of the connected app, hardcoded
NotBefore: notToBeUsedBefore.Unix(),
Subject: clientID,
Id: id.String(),
},
}
//token_header map[string]interface{}
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
sha1Fingerprint := sha1.Sum(cert.Raw)
var slice []byte
slice = sha1Fingerprint[:]
b64FingerPrint := base64.StdEncoding.EncodeToString([]byte(slice))
token.Header["x5t"] = b64FingerPrint
signKey, err := jwt.ParseRSAPrivateKeyFromPEM(pembytes) // parse the RSA key
tokenString, err := token.SignedString(signKey) // sign the claims with private key
fmt.Printf(fmt.Sprintf("JWT token is %s", tokenString))
return tokenString, err
}
I need the help to resolve this issue.
In sqaureup application Aplication_name in oauth option there is a redirect url Which will redirect a given url with the QueryString code. While I'm hitting https://connect.squareup.com/oauth2/authorize?client_id=YOUR_CLIENT_ID this url in the browser then it will redirect me to a given url in oauth with attached code. And then to take a access_token you have to give a POST request to given url https://connect.squareup.com/oauth2/token with the body
{
"client_id": "YOUR_APPLICATION_ID",
"client_secret": "YOUR_APPLICATION_SECRET",
"code": "M-Q7k-N0Emx_3cBqwbVLTQ",
"redirect_uri": "YOUR_REDIRECT_URI"
}
I do it same and send By method POST to this url with json data but it will gives me the error:-
{
"message": "Not Authorized",
"type": "service.not_authorized"
}
The Golang Code I'm using for this is :-
func Token(c *gin.Context) {
code := c.Query("code") // code be something like:-sq0cgp-wLVQt5HOLfug6xiVdmCDCf
splitCode := strings.Split(code, "-")
token := models.PostToken{
ClientID: "YOUR_APPLICATION_ID",
ClientSecret: "YOUR_APPLICATION_SECRET",
Code: splitCode[1],
RedirectUri: c.Request.Host + c.Request.URL.RequestURI(),
}
bindData, err := json.Marshal(token)
if err != nil {
panic(err)
}
var jsonStr = []byte(string(bindData))
url := "https://connect.squareup.com/oauth2/token"
req, err := http.Post(url, "application/json", bytes.NewBuffer(jsonStr))
fmt.Println(req, err)
}
Models struct:-
type PostToken struct {
ClientID string `json:"client_id" bson:"client_id"`
ClientSecret string `json:"client_secret" bson:"client_secret"`
Code string `json:"code" bson:"code"`
RedirectUri string `json:"redirect_uri" bson:"redirect_uri"`
}
You have to do some points I mentioned:-
First check your application Id.
In second parameter ClientSecret you have to use Oauth Application Secret key Which you will got from the application dashboard -> Oauth option.
In Code you don't have send the split code send simple string code value which your getting in the variable name code.
Fourth parameter is optional as the documentation says here.
Then you will got what you want :D.
Here I have a function in which I'm sending a POST request which is used to save customer in the squareup with data and also set the headers with Authentication using variable_name.Header.Set()
But in body response it will always give me error of the:-
"errors":[
{"category":"AUTHENTICATION_ERROR",
"code":"UNAUTHORIZED",
"detail":"Your request did not include an `Authorization` http header with an access token. }]}
But In the function I'm setting the authentication token.
Code:-
func CreateCustomer(c *gin.Context) {
customer := models.Customer{}
bearer := strings.Split(c.Request.Header["Authorization"][0], "Bearer")// token pass in the postman.
bearerToken := strings.TrimSpace(bearer[1])
customerErr := json.NewDecoder(c.Request.Body).Decode(&customer)
if customerErr != nil {
fmt.Println(customerErr)
return
}
fmt.Println(customer)
bindData, err := json.Marshal(customer)
if err != nil {
panic(err)
}
var jsonStr = []byte(string(bindData))
url :="https://connect.squareup.com/v2/customers"
fmt.Println(url)
req, err := http.Post(url, "application/json", bytes.NewBuffer(jsonStr))
// I used this one too.
// req.Header.Set("Authorization", "Bearer "+bearerToken)
// req.Header.Set("Accept", "application/json")
req.Header.Add("Authorization", "Bearer "+bearerToken)
req.Header.Add("Accept", "application/json")
fmt.Println(req.Header)
if err != nil {
panic(err)
}
defer req.Body.Close()
body, _ := ioutil.ReadAll(req.Body)
fmt.Println("response Body:", string(body))
}
type Customer struct {
GivenName string `json:"given_name" bson:"given_name"`
FamilyName string `json:"family_name" bson:"family_name"`
CompanyName string `json:"company_name" bson:"company_name"`
Nickname string `json:"nickname" bson:"nickname"`
EmailAddress string `json:"email_address" bson:"email_address"`
Address Addresss `json:"address" bson:"address"`
PhoneNumber string `json:"phone_number" bson:"phone_number"`
ReferenceId string `json:"reference_id" bson:"reference_id"`
Note string `json:"note" bson:"note"`
}
The req.Header result is:-
map[X-Xss-Protection:[1; mode=block]
Keep-Alive:[timeout=60]
Accept:[application/json]
X-Permitted-Cross-Domain-Policies:[none]
Content-Type:[application/json]
Vary:[Origin, Accept-Encoding]
X-Content-Type-Options:[nosniff]
X-Download-Options:[noopen]
X-Frame-Options:[SAMEORIGIN]
Date:[Wed, 12 Dec 2018 03:41:16 GMT]
Strict-Transport-Security:[max-age=631152000]
Authorization:[Bearer YOUR_TOKEN HERE]]
Can anyone tell me that what error should I'm doing or where I do correction that it will able to save customer in the Squareup?
Your code sends POST request and after request is processed it adds headers to response struct:
response, err := http.Post(url, "application/json", bytes.NewBuffer(jsonStr))
You should set headers first and send request after that:
// create request
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
if err != nil {
panic(err)
}
// set headers
req.Header.Add("Authorization", "Bearer "+bearerToken)
req.Header.Add("Accept", "application/json")
// send request with headers
client := &http.Client{}
response, err := client.Do(req)
#Dmitry Harnitski this is the correct approach. Only reminder is that, try not confused between "authentication" and "authorization", which was kind of roadblock I encountered. It's not about literally meaning, everyone knows the difference. However, even in the syntax, a lot material used these two words interchangeably, which should not be encouraged, at least to my mind. The topic above is a good example: began with "authentication" as the question, then ended with "authorization" as the solution.
I have created a custom installer for a game. I need to update version of my installer with a new feature. The game needs to register to play online. So I need to embed register form from web page (or use HTML codes directly into Inno Setup pages after installation done. So people doesn't need to visit page and able to register play online via Inno Setup.
Create a new page in installer with embedded browser in it.
I recommend to use this component: https://code.google.com/p/inno-web-browser/
Usage is really simple: https://code.google.com/p/inno-web-browser/source/browse/trunk/Example.iss
When user advances to your (newly created) page, navigate to your website (which should be running somewhere on server).
There's no native support for including a web page to Inno Setup installer. Neither I'm aware of any 3rd party extension that would support it.
Instead, you can code a custom installer page using the CreateInputQueryPage function to query user registration details and send them to your web site.
A simple example:
[Code]
var
UserPage: TInputQueryWizardPage;
procedure InitializeWizard;
begin
UserPage := CreateInputQueryPage(wpWelcome,
'Registration', 'Who are you?',
'Please specify your name and username tor register, then click Next.');
UserPage.Add('Name:', False);
UserPage.Add('User name:', False);
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
Result := True;
if CurPageID = UserPage.ID then
begin
if (UserPage.Values[0] = '') or (UserPage.Values[1] = '') then
begin
MsgBox('You must enter your name and username.', mbError, MB_OK);
Result := False;
end;
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
WinHttpReq: Variant;
RegisterUrl: string;
begin
if CurStep = ssDone then
begin
try
RegisterUrl :=
'https://www.example.com/register.php?' +
Format('name=%s&username=%s', [UserPage.Values[0], UserPage.Values[1]])
Log('Sending registration request: ' + RegisterUrl);
WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
WinHttpReq.Open('GET', RegisterUrl, False);
WinHttpReq.Send('');
Log('Registration report send result: ' +
IntToStr(WinHttpReq.Status) + ' ' + WinHttpReq.StatusText);
except
Log('Error sending registration report: ' + GetExceptionMessage);
end;
end;
end;
(Note that this lacks URL-encoding of the data).
Or simply open the registration form at the end of the installation in a web browser.
[Run]
Filename: "https://www.example.com/register.php"; \
Description: "&Open registration form"; \
Flags: shellexec runasoriginaluser postinstall