How Customise NOP Commerce eWayHosted Plugin For Other Payment Gateway - asp.net-mvc

I want to customize nopCommerce eWayHosted plugin for other payment gateway(Easy Pay). I change the payment URL and the parameters.
public void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest)
{
var strPost = "storeId=" + _eWayHostedPaymentSettings.CustomerId;
strPost += Format("amount", postProcessPaymentRequest.Order.OrderTotal.ToString("0.00", CultureInfo.InvariantCulture));
strPost += Format("orderRefNum", postProcessPaymentRequest.Order.Id.ToString());
strPost += Format("postBackURL", "http://www.smmotors.org/onepagecheckout");
var url = _eWayHostedPaymentSettings.PaymentPage + "?" + strPost;
var objRequest = (HttpWebRequest)WebRequest.Create(url);
objRequest.Method = WebRequestMethods.Http.Get;
var objRequest1 = (HttpWebRequest)WebRequest.Create(url);
objRequest1.Method = WebRequestMethods.Http.Post;
var objResponse = (HttpWebResponse)objRequest.GetResponse();
At this point
The Easypay server sends back a parameter named auth_token to the postbackURL which is sent as a GET parameter.
But Var objResponse cannot get auth_token & postBackURL. Whats The Reason & solution
//get the response from the transaction generate page
string resultXml;
using (var sr = new StreamReader(objResponse.GetResponseStream()))
{
resultXml = sr.ReadToEnd();
// Close and clean up the StreamReader
sr.Close();
}
//parse the result message
var resultObj = ParseRequestResults(resultXml);
if (resultObj.Result)
{
//redirect the user to the payment page
HttpContext.Current.Response.Redirect(resultObj.Uri);
}
else
{
throw new NopException(resultObj.Error);
}
}
Below Is The Plug-in Integration Steps:
Following process will be followed by merchants to embed the Easypay Plug-in in their stores:
• Merchant acquires an account through Easypay agents. A Welcome email containing unique Store ID and URL is sent to the Merchant after successful registration.
• Merchant logins the Easy Pay portal and access ‘Guide to Integration’ menu where Merchant is presented with step by step instructions to integrate the Easypay plug- in to their shopping cart/online retail shop.
Following is the sample of flow merchant should find after logging into the Easypay portal.
Merchants having unique store ID embed Easypay plug-in on checkout page of their online stores/ websites. This will integrate “Pay through Easypay as a payment solution in their websites. The integration of Easypay plug-in is a simple two-step process:
The merchant needs to POST following parameter to the Easypay on the f o l l owi n g URL:
Production (Live) Environment:
https://easypay.easypaisa.com.pk/easypay/Index.jsf
Sandbox Environment:
https://easypaystg.easypaisa.com.pk/easypay/Index.jsf
• amount
• storeId
• postBackURL
• orderRefNum
After successful redirection the customer would land on the Easypay Checkout Screen where there is a form to be filled regarding the transaction information.
After completing the form in Step 1 the customer will be pressing the Proceed Button and lands back on the merchant website on the same URL given in postbackURL variable in the first step. This will be a confirmation screen on merchant’s website to perform a handshake between Easypay and merchant’s website. The Easypay sends back a parameter named auth_token to the postbackURL which is sent as a GET parameter. Now the merchant needs to post back following two parameters again to the following URL:
Production (Live) Environment:
https://easypay.easypaisa.com.pk/easypay/Confirm.jsf
Sandbox Environment:
https://easypaystg.easypaisa.com.pk/easypay/Confirm.jsf
• auth_token
• postBackURL
After this redirection the Easypay authenticates the auth_token sent by merchant with the one it has in the previous step, and upon successful authentication it will make customer land on the successful checkout screen sending back following two variables to the second postBackURL:
• status
• desc
• orderRefNumber
Sample Code Snippet for .NET
For the first redirection:
using (var client = new HttpClient())
{
var values = new List<KeyValuePair<string, string>>();
values.Add(new KeyValuePair<string, string>("storeId", "43"));
values.Add(new KeyValuePair<string, string>("amount", "10"));
values.Add(new KeyValuePair<string, string>("postBackURL", "http://www.my.onlinestore.com/transaction/MessageHandler"));
values.Add(new KeyValuePair<string, string>("orderRefNum", "1101"));
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("https://easypay.easypaisa.com.pk/easypay/Index.jsf", content); var responseString = await response.Content.ReadAsStringAsync();
}
For the second redirection:
using (var client = new HttpClient())
{
var values = new List<KeyValuePair<string, string>>();
values.Add(new KeyValuePair<string, string>("auth_token", Request.Querystring["auth_token"])); values.Add(new KeyValuePair<string, string>("postBackURL", "http://www.my.online-
store.com/transaction/MessageHandler1"));
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("https://easypay.easypaisa.com.pk/easypay/Confirm.jsf", content); var responseString = await response.Content.ReadAsStringAsync();
}

Related

Sign In using raw HttpRequestMessage in ASP.NET MVC

I have been testing some code to sign in users to their Microsoft/school/work accounts using raw HttpRequestMessage and HttpResponseMessage. I know there are libraries available to do this but I want to test the raw approach as well (especially usage of refresh tokens), while looking for the right library to handle it.
I'm currently learning authentication, with limited knowledge of ASP.NET/Core.
I'm following this guide: https://learn.microsoft.com/en-us/graph/auth-v2-user
I've just modified the SignIn() method in AccountController in an example project that used more high level libraries to sign in.
I'm requesting an authorization code.
The SignIn() code:
public void SignIn()
{
using (var httpClient = new HttpClient())
{
try
{
var tenant = "my tenant id";
var clientId = ConfigurationManager.AppSettings["ida:AppID"];
var responseType = "id_token+code";
var redirectURI = ConfigurationManager.AppSettings["ida:RedirectUri"];
var responseMode = "form_post";//query";
var appScopes = ConfigurationManager.AppSettings["ida:AppScopes"];
var scopes = $"openid profile offline_access {appScopes}";
var state = "12345";
//var prompt = "consent";
var url = string.Format("https://login.microsoftonline.com/{0}/oauth2/v2.0/authorize", tenant);
var body = string.Format("client_id={1}&response_type={2}&redirect_uri={3}&response_mode={4}&scope={5}&state={6}", tenant, clientId, responseType, redirectURI, responseMode, scopes, state);
var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Content = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded");
var response = httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead).Result;
var content = response.Content.ReadAsStringAsync().Result;
}
catch (Exception ex)
{
}
}
//if (!Request.IsAuthenticated)
//{
// // Signal OWIN to send an authorization request to Azure
// Request.GetOwinContext().Authentication.Challenge(
// new AuthenticationProperties { RedirectUri = "/" },
// OpenIdConnectAuthenticationDefaults.AuthenticationType);
//}
}
I'm just returning void from the method now because I'm not sure what I should return yet.
Debugging and looking at the response variable, the status code is 200, and has some other information to it. However, the content of the HttpResponseMessage, when I paste it into a file and opening it in a browser, displays (or redirects to) https://login.microsoftonline.com/cookiesdisabled, which shows a message saying that I could not be logged in because my browser blocks cookies. However, I don't think this really is the case.
How can I resolve this and have the user log in and consent, and get the authorization code?
I couldn't really find any example in ASP.NET that uses this raw approach. Is it not recommended?
You should fistly understand how OAuth 2.0 authorization code flow works in Azure AD V2.0 :
Microsoft identity platform and OAuth 2.0 authorization code flow
The general process would be like :
When login in client application, user will be redirect to Azure AD login endpoint(https://login.microsoftonline.com/{0}/oauth2/v2.0/authorize) and provides info like which client(client_id) in which tenant(tenant id) user wants to login , and redirect back to which url(redirect_uri) after successful login.
User enter credential , Azure AD validate credential and issue code and redirect user back to redirect url provided in step 1 (Also match one of the redirect_uris you registered in the portal).
The client application will get the code and send http post request with code to acquire access token .
So if you want to manally implement the code flow in your application , you can refer to below code sample :
public async Task<IActionResult> Login()
{
string authorizationUrl = string.Format(
"https://login.microsoftonline.com/{0}/oauth2/v2.0/authorize?response_type=code&client_id={1}&redirect_uri={2}&scope={3}",
"tenantID", "ClientID", "https://localhost:44360/Home/CatchCode",
"openid offline_access https://graph.microsoft.com/user.read");
return Redirect(authorizationUrl);
}
private static readonly HttpClient client = new HttpClient();
public async Task<ActionResult> CatchCode(string code)
{
var values = new Dictionary<string, string>
{
{ "grant_type", "authorization_code" },
{ "client_id", "XXXXXX"},
{ "code", code},
{ "redirect_uri", "https://localhost:44360/Home/CatchCode"},
{ "scope", "https://graph.microsoft.com/user.read"},
{ "client_secret", "XXXXXXXXXXX"},
};
var content = new FormUrlEncodedContent(values);
//POST the object to the specified URI
var response = await client.PostAsync("https://login.microsoftonline.com/cb1c3f2e-a2dd-4fde-bf8f-f75ab18b21ac/oauth2/v2.0/token", content);
//Read back the answer from server
var responseString = await response.Content.ReadAsStringAsync();
//you can deserialize an Object use Json.NET to get tokens
}
That just is simple code sample which will get Microsoft Graph's access token , you still need to care about url encode and catch exception , but it shows how code flow works .

Set url for GraphApi B2C login

I need to query the Graph API to get the username in the claims.
I've implemented something based on what I've found on the net, but I keep getting 403 Forbidden, from Graph API.
Can anyone help me with this?
This is my code:
var clientId = "clientId";
var clientSecret = "clienSecret";
var tenant = "tenantName";
var userObjectId = claimsPrincipal.Claims.Where(i => i.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier").FirstOrDefault().Value;
var aadGraphVersion = "api-version=1.6";
var query = "/users/" + userObjectId;
AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/" + tenant);
// The ClientCredential is where you pass in your client_id and client_secret, which are
// provided to Azure AD in order to receive an access_token using the app's identity.
ClientCredential credential = new ClientCredential(clientId, clientSecret);
// First, use ADAL to acquire a token using the app's identity (the credential)
// The first parameter is the resource we want an access_token for; in this case, the Graph API.
AuthenticationResult result = await authContext.AcquireTokenAsync("https://graph.windows.net", credential);
// For B2C user management, be sure to use the Azure AD Graph API for now.
HttpClient http = new HttpClient();
//var url = "https://graph.windows.net/" + tenant + "/users/" + userObjectId + "/?api-version=1.6";
//var url = graphResource + "tenant" + "/users/" + userObjectId + "/?api-version=1.6";
string url = "https://graph.windows.net/" + tenant + "/users/" + userObjectId + "?" + aadGraphVersion;
//url += "&" + query;
// Append the access token for the Graph API to the Authorization header of the request, using the Bearer scheme.
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = await http.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
string error = await response.Content.ReadAsStringAsync();
object formatted = JsonConvert.DeserializeObject(error);
throw new WebException("Error Calling the Graph API: \n" + JsonConvert.SerializeObject(formatted, Formatting.Indented));
}
I think I have a problem with the URL that is not set correctly. The token is correct, I got it ok with the credentials.
I do think it is an issue with the URL. You are getting this error as you have provided user read permissions to your registered application. Please make sure that -
You go to Application registrations menu on your tenant
Select "Required Permissions" menu and click on Windows Azure Active Directory
In the "Enable Access" menu select "Read Directory Data" permissions under Application Permissions section and click save.
Once saved on "Required Permissions" menu click on "Grant Permissions" button to provide the consent.
You may need to select other options like "Read and Write Directory Data" if you wish to provide your application to create/update/delete users.

Uploading a x509 cert to Application Manifest on Azure ADD or Microsoft Registration Portal

Sorry for the multiple post about the same issue!
I'm trying to upload a self signed sertificate to application manifest created on Microsoft Registration Portal but I have some issues which I don't completly understand why, According to this answer, it's very much possible to upload the certificate using DELEGATED PERMISSIONS however I don't see the reason why I can't use Application Permissions since I only need the AccessToken and I get that with the client_credential grant flow,
Below is the code that I have tried but when retrieving the token with client_credential grant flow, I get stuck att var application = activeDirectoryClient.Applications["ApplicationObjectId"].ExecuteAsync().Result;
and when trying to use the code given to my by Tom Sung in the previous post, the applications exits with error "must have client_credentil or client_assertion in request body"
this is the code that I have tried:
private static async Task<string> GetAppTokenAsync(string graphResourceId, string tenantId, string clientId, string userId)
{
string aadInstance = "https://login.microsoftonline.com/" + tenantId + "/oauth2/token";
var clientCredential = new ClientCredential(clientId, clientSecret);
AuthenticationContext authenticationContextt =
new AuthenticationContext($"https://login.microsoftonline.com/{tenantId}/oauth2/token");
AuthenticationResult result =
await authenticationContextt.AcquireTokenAsync(graphResourceId,
clientCredential);
//token is acquiered and gets stuck
var e = result.AccessToken;
//Tom Suns code
IPlatformParameters parameters = new PlatformParameters(PromptBehavior.SelectAccount);
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance);
var authenticationResult = await authenticationContext.AcquireTokenAsync(graphResourceId, clientId, new Uri("http://localhost"), parameters, new UserIdentifier(userId, UserIdentifierType.UniqueId));
//exits with error
return authenticationResult.AccessToken;
}
try
{
var graphResourceId = "https://graph.windows.net";
var userId = "****";
//used to test if token is acquired
//var tokennn = await GetAppTokenAsync(graphResourceId, tenantID, ClientId, userId);
var servicePointUri = new Uri(graphResourceId);
var serviceRoot = new Uri(servicePointUri, tenant);
var activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await GetAppTokenAsync(graphResourceId, tenantID, ClientId, userId));
AsymmetricKeyParameter myCAprivateKey = null;
//generate a root CA cert and obtain the privateKey
X509Certificate2 MyRootCAcert = CreateCertificateAuthorityCertificate("CN=OutlookIntegration", out myCAprivateKey);
//add CA cert to store
addCertToStore(MyRootCAcert, StoreName.Root, StoreLocation.LocalMachine);
var expirationDate = DateTime.Parse(MyRootCAcert.GetExpirationDateString()).ToUniversalTime();
var startDate = DateTime.Parse(MyRootCAcert.GetEffectiveDateString()).ToUniversalTime();
var binCert = MyRootCAcert.GetRawCertData();
var keyCredential = new KeyCredential
{
CustomKeyIdentifier = MyRootCAcert.GetCertHash(),
EndDate = expirationDate,
KeyId = Guid.NewGuid(),
StartDate = startDate,
Type = "AsymmetricX509Cert",
Usage = "Verify",
Value = binCert
};
//gets stuck here when using clientsecret grant type
var application = activeDirectoryClient.Applications["ApplicationObjectId"].ExecuteAsync().Result;
application.KeyCredentials.Add(keyCredential);
application.UpdateAsync().Wait();
}
catch (Exception exception)
{
Console.WriteLine(exception);
throw;
}
I am now completly stuck, Anyone have any idea why it doesn't work with Application Permissions or why it gets stuck at var application = activeDirectoryClient.Applications["ApplicationObjectId"].ExecuteAsync().Result;
Edit 1
is it because I have my app as a web app/API that uses username and password to authenticate?
Based on my test if we want to change the keyCredential, DELEGATED PERMISSIONS is required.
If we want to update Azure AD application other properties, we could use Application Permissions.
Reference:
Azure Active Directory developer glossary
"Delegated" permissions, which specify scope-based access using delegated authorization from the signed-in resource owner, are presented to the resource at run-time as "scp" claims in the client's access token.
"Application" permissions, which specify role-based access using the client application's credentials/identity, are presented to the resource at run-time as "roles" claims in the client's access token.

Oauth2 and Access Token in SharePoint App

I am creating an intranet on SharePoint - O365 where I can a widget where I need to pull calendar events and display them for a week. Here is a steps walk through:
a. User log in to Intranet
b. Access token is generated to access Office 365 REST API
c. Calendar events are fetched and displayed.
Here is my problem:
I thought of 2 options to generate the access token
option a: Create a WCF application which accpets user context and generate the token. This will fetch the results and update a list. My intranet app can read a calendar list and update the widget. This didnt work since I was not able to pass the user context from SP to WCF method so that access token can be generated.
Option b: Use the following code (which I have done as of now) but it display the access token in URL which is not good for the client.
var clientId = '>>sample>>';
var replyUrl = '<<>>';
var endpointUrl = 'https://outlook.office365.com/api/v1.0/me/events';
var resource = "https://outlook.office365.com/";
var authServer = 'https://login.windows.net/common/oauth2/authorize?';
var responseType = 'token';
var url = authServer +
"response_type=" + encodeURI(responseType) + "&" +
"client_id=" + encodeURI(clientId) + "&" +
"resource=" + encodeURI(resource) + "&" +
"redirect_uri=" + encodeURI(replyUrl);
window.location = url;
So is there any other way to achieve this??
Ankush
Since you mentioned that you want to use the WCF, are you developing an provided host SharePoint app?
If I understand correctly, we can use the Explicit Authorization Code Grant Flow which didn’t expose the Access token to the user agent. The following diagram illustrates the Authorization Code Grant flow:
And here is the core code to retrieve the access token for the Office 365 resource for you reference:
var signInUserId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
var userObjectId = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.Authority, new ADALTokenCache(signInUserId));
try
{
DiscoveryClient discClient = new DiscoveryClient(SettingsHelper.DiscoveryServiceEndpointUri,
async () =>
{
var authResult = await authContext.AcquireTokenSilentAsync(SettingsHelper.DiscoveryServiceResourceId,
new ClientCredential(SettingsHelper.ClientId,
SettingsHelper.ClientSecret),
new UserIdentifier(userObjectId,
UserIdentifierType.UniqueId));
string token= authResult.AccessToken;
return authResult.AccessToken;
});
var dcr = await discClient.DiscoverCapabilityAsync(capabilityName);
return new OutlookServicesClient(dcr.ServiceEndpointUri,
async () =>
{
var authResult = await authContext.AcquireTokenSilentAsync(dcr.ServiceResourceId,
new ClientCredential(SettingsHelper.ClientId,
SettingsHelper.ClientSecret),
new UserIdentifier(userObjectId,
UserIdentifierType.UniqueId));
return authResult.AccessToken;
});
}
The full code sample you can refer to here. And here is a helpful link that discuss the difference between explicit and implicate authentication flow.

Always "This transaction is invalid..." on live PayPal for ASP.NET

I am developing web application on ASP.NET. In application users can purchase article for money.
For work with PayPal I using PayPal Merchant SDK for .NET package. Application work good with sandbox but with live display error: "This transaction is invalid". Please return to the recipient's website to complete your transaction using their regular checkout flow."
When user click on purchase button I execute code:
// only for live
var paypalConfig = new Dictionary<string, string> {
{"account1.applicationId", "<APP-LIVEID>"},
{"account1.apiUsername", "<username>"},
{"account1.apiPassword", "<pass>"},
{"account1.apiSignature", "<signature>"},
{"mode", "live"}};
try
{
var currency = CurrencyCodeType.USD;
var paymentItem = new PaymentDetailsItemType
{
Name = "item",
Amount = new BasicAmountType(currency, amount.ToString()),
ItemCategory = ItemCategoryType.DIGITAL,
};
var paymentItems = new List<PaymentDetailsItemType>();
paymentItems.Add(paymentItem);
var paymentDetail = new PaymentDetailsType();
paymentDetail.PaymentDetailsItem = paymentItems;
paymentDetail.PaymentAction = PaymentActionCodeType.SALE;
paymentDetail.OrderTotal = new BasicAmountType(currency, amount.ToString());
paymentDetail.SellerDetails = new SellerDetailsType {
PayPalAccountID= sellerEmail
};
var paymentDetails = new List<PaymentDetailsType>();
paymentDetails.Add(paymentDetail);
var ecDetails = new SetExpressCheckoutRequestDetailsType {
ReturnURL = returnUrl,
CancelURL = cancelUrl,
PaymentDetails = paymentDetails,
};
var request = new SetExpressCheckoutRequestType
{
Version = "104.0",
SetExpressCheckoutRequestDetails = ecDetails,
};
var wrapper = new SetExpressCheckoutReq
{
SetExpressCheckoutRequest = request
};
var service = new PayPalAPIInterfaceServiceService(paypalConfig);
var setECResponse = service.SetExpressCheckout(wrapper);
if (sandbox)
return "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}".FormatWith(setECResponse.Token);
return "https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&TOKEN={0}".FormatWith(setECResponse.Token);
}
// # Exception log
catch (System.Exception ex)
{
// Log the exception message
Console.WriteLine("Error Message : " + ex.Message);
}
After all I redirect user to url with received TOKEN.
For my application, registered on PayPal, I set in options only "Adaptive Payments > Basic Payments > Checkout, Send Money or Parallel Payments"
Why live paypal payments can not work? What is the reason?
Removed
ItemCategory = ItemCategoryType.DIGITAL,
and all work
From previous experiences this problem usually comes from having a "null" token because of some mistake in the "setExpressCheckout" request (where, in the express checkout flow, you ask paypal for a transaction token).
Basically, you ask paypal for a token so you can build the redirect URL, but you make some mistake and paypal gives you an error but no token, so you build the URL with no token (or a wrong one).
If you try to redirect the user to the checkout URL ( https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={...}&useraction={...}) with an empty token you will get this error.
Actually I'm trying to know of there can be other causes...

Resources