Server side validation for Cloudfare Turnstile reCaptcha - asp.net-core-webapi

I am adding CF Turnstile recaptcha to my asp.net core web api for our contact us form and I am curious what IP address I should be using for this verification process. My code is as follows:
var dictionary = new Dictionary<string, string>
{
{ "secret", reCaptchaKey },
{ "response", customerInquiry.Token }
};
var postContent = new FormUrlEncodedContent(dictionary);
HttpResponseMessage recaptchaResponse = null;
string stringContent = "";
// Call recaptcha api and validate the token
using (var http = new HttpClient())
{
recaptchaResponse = await http.PostAsync("https://challenges.cloudflare.com/turnstile/v0/siteverify", postContent);
stringContent = await recaptchaResponse.Content.ReadAsStringAsync();
}
The example code on CF shows the following for their node.js ( I assume) implementation:
formData.append('secret', SECRET_KEY);
formData.append('response', token);
formData.append('remoteip', ip);

Related

How to use Graph API Sharepoint Search from console app

I have created a .net core console application to access the graph api. I created a authentication by using clientId and clientSecret of the Azure AD application
string tenantName = "MY.TENANT";
string authUrl = "https://login.microsoftonline.com/" + tenantName;
var clientId = "MYID";
var clientSecret = "MYSECRET";
AuthenticationContext authenticationContext = new AuthenticationContext(authUrl, false);
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);
AuthenticationResult authenticationResult;
authenticationResult = await authenticationContext.AcquireTokenAsync("https://graph.microsoft.com/", clientCred);
return authenticationResult.AccessToken;
After I get a valid token the call do a sharepoint list works fine and I get some data
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, $"{graphUrl}/sites/{siteId}/lists/MYLISTGUID/items?expand=fields");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var responseString = response.Content.ReadAsStringAsync().Result;
return responseString;
}
But if I call the Search API I get the following error: SearchRequest Invalid (Region is required when request with application permission.)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, $"{graphUrl}/search/query/");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
var filter = new
{
Requests = new[] {
new {
EntityTypes = new[] { "listItem" },
Query = new
{
QueryString = "Pio*"
}
}
}
};
request.Content = new StringContent(JsonConvert.SerializeObject(filter), Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var responseString = response.Content.ReadAsStringAsync().Result;
}
The same query by using the Graph Explorer works fine.
I found some posts around that tells something, that you can not call the search API by using the application credential but only by using delegation. In my case the api call is made by a service user and not by the user directly. I have to migrate a Sharepoint on Premise solution which access the search in that way.
Thanks for any input
You can get the region value by calling the following URL
https://yourtenant.sharepoint.com/_api/GeoTenantInstanceInformationCollection
Note: your tenant admin needs to call (copy&paste in the browser) this URL otherwise you will receive UnauthorizedAccessException with the message Current user is not a tenant administrator.
Then add region property with the value from the request above to your filter:
var filter = new
{
Requests = new[] {
new {
EntityTypes = new[] { "listItem" },
Query = new
{
QueryString = "Pio*"
},
Region = "guid"
}
}
};
Resources:
Search content with application permissions

Sending and getting http headers

I am working on an asp.net Web API and I have an web application that consumes this api.
Right now it is working perfectly since I don't have the [Authorize] part on my api controller.
So, if I want to secure this api, my web application will not be able anymore to fetch data from the API because it is not authorized.
So how can I send the token generated from my API to my web app and to allow it to fetch the needed data?
-I am using postman for testing my app;
-my api return jwt token;
-I am not really familiar with http headers.
My consuming web application controller :
public ActionResult Index()
{
IEnumerable<OperatorClass> OperatorObject = null;
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://localhost:44304/api/");
var ApiOpController = client.GetAsync("data");
client.DefaultRequestHeaders.Add("Authorization", "Bearer"+"");
ApiOpController.Wait();
var resultDisplay = ApiOpController.Result;
if (resultDisplay.IsSuccessStatusCode)
{
var readTable = resultDisplay.Content.ReadAsAsync<IList<OperatorClass>>();
readTable.Wait();
OperatorObject = readTable.Result;
}
else
{
OperatorObject = Enumerable.Empty<OperatorClass>();
ModelState.AddModelError(String.Empty, "No records found");
}
return View(OperatorObject);
}
My web API controller
[Authorize]
[HttpGet]
public IHttpActionResult GetOperators()
{
SchoolEntity myEntity = new SchoolEntity ();
IList<OperatorClass> OperatorObject = myEntity.Operator.Include("Operator").Select(x => new OperatorClass()
{
name = x.name,
lastname = x.lastname,
mobile = x.mobile,
username = x.username,
password = x.password
}).ToList<OperatorClass>();
return Ok(OperatorObject);
}
string token = <Your token>
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
this should work for you.
To be able to use your MVC controller, you need to store the token when it returns.
One way to do it is to store it using Session.
Assuming you are using sign in to get the token, anytime you sign in successfully you can store the token using the session. See below.
//For brevity after successful login
string myToken = <token returned from api>
HttpContext.Session.SetString("token", myToken);
//other codes
then you can use this in all of your controllers.
public async Task<ActionResult> Index()
{
IEnumerable<OperatorClass> OperatorObject = null;
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://localhost:44304/api/");
//note here
var token = HttpContext.Session.GetString("token");
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
//ApiOpController.Wait();
var resultDisplay = await client.GetAsync("data");
if (resultDisplay.IsSuccessStatusCode)
{
var readTable = await resultDisplay.Content.ReadAsAsync<IList<OperatorClass>>();
//readTable.Wait();
OperatorObject = readTable;
}
else
{
OperatorObject = Enumerable.Empty<OperatorClass>();
ModelState.AddModelError(String.Empty, "No records found");
}
return View(OperatorObject);
}

.Net Core PayPal: Client Authentication failed

I'm starting to use PayPal for payments with .net Core. I created a sandbox app and checked client id and secret. I get an error at content
"{"error":"invalid_client","error_description":"Client Authentication failed"}"
Code:
private async Task<PayPalAccessToken> GetPayPalAccessTokenAsync(HttpClient httpClient)
{
byte[] bytes = Encoding.GetEncoding("iso-8859-1")
.GetBytes($"{_configuration["PayPal:clientId"]} : {_configuration["PayPal:secret"]}");
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, "/v1/oauth2/token");
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Basic", Convert.ToBase64String(bytes));
var form = new Dictionary<string, string>
{
["grant_type"] = "client_credentials"
};
requestMessage.Content = new FormUrlEncodedContent(form);
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
string content = await responseMessage.Content.ReadAsStringAsync();
PayPalAccessToken accessToken = JsonConvert.DeserializeObject<PayPalAccessToken>(content);
return accessToken;
}
Setting:
"PayPal": {
"clientId": "xxx",
"secret": "xxx",
"urlAPI": "https://api-m.sandbox.paypal.com",
"returnUrl": "https://localhost:44370/cart/success",
"cancelUrl": "https://localhost:44370/cart/cancel"
}
And here is Code I followed https://gist.github.com/jakejscott/1b829ca1c9449e4788710867f346e90f
Full my code https://paste.mod.gg/ayoqinotis.csharp
What is the problem that I am facing?

Microsoft Graph in asp.net web forms access token expires - how to refresh tokens in web forms application and not MVC

I have an asp.net 4.6 web forms application (no MVC). I am updating the security in my application. I am using OpenIdConnectAuthentication to authenticate with our Azure AD. Then I pass the access token to Microsoft graph to send an email with Office 365. My token is set to expire in 60 minutes. I either need to expand the expiration to 8 hours or refresh the token. Without having MVC I am not sure how to handle this. I am looking for help with direction to take and possibly code samples.
(I original tried to utilize an MVC sample and put it into my project using a Session Token class. Once we tested with multiple users I believe I had a memory leak and it would crash in about 5 minutes.)
Startup code:
public class Startup
{
private readonly string _clientId = ConfigurationManager.AppSettings["ClientId"];
private readonly string _redirectUri = ConfigurationManager.AppSettings["RedirectUri"];
private readonly string _authority = ConfigurationManager.AppSettings["Authority"];
private readonly string _clientSecret = ConfigurationManager.AppSettings["ClientSecret"];
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
CookieManager = new SystemWebCookieManager(),
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = _clientId,
ClientSecret = _clientSecret,
//Authority = _authority,
Authority = String.Format(_authority, domain, "/v2.0"),
RedirectUri = _redirectUri,
ResponseType = OpenIdConnectResponseType.CodeIdToken,
Scope = OpenIdConnectScope.OpenIdProfile,
UseTokenLifetime = false,
TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", RequireExpirationTime = false},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async n =>
{
// Exchange code for access and ID tokens
var auth = String.Format(_authority, "common/oauth2/v2.0", "/token");
var tokenClient = new TokenClient($"{auth}", _clientId, _clientSecret);
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, _redirectUri);
if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}
var claims = new List<Claim>()
{
new Claim("id_token", tokenResponse.IdentityToken),
new Claim("access_token", tokenResponse.AccessToken)
};
n.AuthenticationTicket.Identity.AddClaims(claims);
},
},
});
}
}
SDK Helper:
public class SDKHelper
{
// Get an authenticated Microsoft Graph Service client.
public static GraphServiceClient GetAuthenticatedClient()
{
GraphServiceClient graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
async (requestMessage) =>
{
string accessToken = System.Security.Claims.ClaimsPrincipal.Current.FindFirst("access_token").Value;
// Append the access token to the request.
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
// Get event times in the current time zone.
requestMessage.Headers.Add("Prefer", "outlook.timezone=\"" + TimeZoneInfo.Local.Id + "\"");
// This header has been added to identify our sample in the Microsoft Graph service. If extracting this code for your project please remove.
requestMessage.Headers.Add("SampleID", "aspnet-snippets-sample");
}));
return graphClient;
}
}
Sending Email:
GraphServiceClient graphClient = SDKHelper.GetAuthenticatedClient();
string address = emailaddress;
string guid = Guid.NewGuid().ToString();
List<Recipient> recipients = new List<Recipient>();
recipients.Add(new Recipient
{
EmailAddress = new Microsoft.Graph.EmailAddress
{
Address = address
}
});
// Create the message.
Message email = new Message
{
Body = new ItemBody
{
ContentType = Microsoft.Graph.BodyType.Text,
},
Subject = "TEST",
ToRecipients = recipients,
From = new Recipient
{
EmailAddress = new Microsoft.Graph.EmailAddress
{
Address = address
}
}
};
// Send the message.
try
{
graphClient.Me.SendMail(email, true).Request().PostAsync().Wait();
}
catch (ServiceException exMsg)
{
}
You need to request the scope offline_access. Once you've requested that, the /token endpoint will return both an access_token and a refresh_token. When your token expires, you can make another call to the /token endpoint to request a new set of access and refresh tokens.
You might find this article helpful: Microsoft v2 Endpoint Primer. In particular, the section on refresh tokens.

ASP.NET Boilerplate Auth from Windows Phone 8.1 - bearer token

I'm using asp.net boilerplate for my website. There I have standard authentication from aspnetboilerplate/module-zero(OWIN).
But now I need athentication for my windows phone app(wp8.1)
I was trying configure my application for authorization with bearer but I failed..
How configurate asp.net boilerplate application for my windows phone app auth?
In windows phone app I send post to my web api like this:
public static async Task<TokenResponseModel> GetBearerToken(string siteUrl, string Username, string Password)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(siteUrl);
client.DefaultRequestHeaders.Accept.Clear();
HttpContent requestContent = new StringContent("grant_type=password&username=" + Username + "&password=" + Password, Encoding.UTF8, "application/x-www-form-urlencoded");
HttpResponseMessage responseMessage = await client.PostAsync("Token", requestContent);
if (responseMessage.IsSuccessStatusCode)
{
string jsonMessage;
using (Stream responseStream = await responseMessage.Content.ReadAsStreamAsync())
{
jsonMessage = new StreamReader(responseStream).ReadToEnd();
}
TokenResponseModel tokenResponse = (TokenResponseModel)JsonConvert.DeserializeObject(jsonMessage, typeof(TokenResponseModel));
return tokenResponse;
}
else
{
return null;
}
}
But what should I do in WebApi? How auth and next response bearer and how auth in next step using bearer when on class i have [AbpAuthorize]?
This now documented and implemented in module zero template
code:
In module WebApi:
Configuration.Modules.AbpWebApi().HttpConfiguration.Filters.Add(new HostAuthenticationFilter("Bearer"));
In controller WebApi:
[HttpPost]
public async Task<AjaxResponse> Authenticate(LoginModel loginModel)
{
CheckModelState();
var loginResult = await GetLoginResultAsync(
loginModel.UsernameOrEmailAddress,
loginModel.Password,
loginModel.TenancyName
);
var ticket = new AuthenticationTicket(loginResult.Identity, new AuthenticationProperties());
var currentUtc = new SystemClock().UtcNow;
ticket.Properties.IssuedUtc = currentUtc;
ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromMinutes(30));
return new AjaxResponse(OAuthBearerOptions.AccessTokenFormat.Protect(ticket));
}
documentation: http://aspnetboilerplate.com/Pages/Documents/Zero/Startup-Template#token-based-authentication

Resources