public void HandleAuthorizationRequest(NameValueCollection parameters, HttpResponse response) { logger.Info("Handling /authorize with ExampleAuthorizationHandler"); logger.Debug("Verifying Signature..."); bool validSignature = SignatureUtils.Signature(parameters, Constants.SECRET).Equals(parameters["signature"]); if (!validSignature) { /** * InvalidSignatureException * Invalid Signature is a special case of exception that throws an HTTP Error. With the * exception of Invalid Signature and Internal Server errors, it is expected that the callback * response be properly formatted XML per the PayNearMe specification. * * This is a security exception and may highlight a configuration problem (wrong secret or * siteIdentifier) OR it may highlight a possible payment injection from a source other than * PayNearMe. You may choose to notify your IT department when this error class is raised. * PayNearMe strongly recommends that your callback listeners be whitelisted to ONLY allow * traffic from PayNearMe IP addresses. * * When this class of error is raised in a production environment you may choose to not respond * to PayNearMe, which will trigger a timeout exception, leading to PayNearMe to retry the * callbacks up to 40 times. If the error persists, callbacks will be suspended. * * In development environment this default message will aid with debugging. */ logger.Error("Invalid signature, declining authorization request."); } // If the url contains the parameter test=true (part of the signed params too!) then we flag this. // Do not handle test=true requests as real requests. bool isTest = parameters["test"] != null && Boolean.Parse(parameters["test"]); if (isTest) { logger.Info("This authorize request is a TEST!"); } // Special behavior for testing/demonstration string special = parameters["site_order_annotation"]; if (special != null) { if (special.StartsWith("confirm_delay_")) { int delay = Convert.ToInt32(special.Substring(special.LastIndexOf('_') + 1)) * 1000; logger.Info("Delaying response by " + delay + " seconds"); Thread.Sleep(delay); } else if (special.Equals("confirm_bad_xml")) { logger.Info("Responding with bad/broken xml"); response.Output.Write("<result"); response.Output.Flush(); logger.Debug("End handleConfirmationRequest (early: bad xml)"); return; } else if (special.Equals("confirm_blank")) { logger.Info("Responding with a blank/empty response"); logger.Debug("End handleConfirmationRequest (early: blank response)"); return; } else if (special.Equals("confirm_redirect")) { logger.Info("Redirecting to /"); response.Redirect("/"); logger.Debug("End handleConfirmationRequest (early: redirect)"); return; } } else { logger.Debug("No special behavior specified by site_order_annotation"); } String pnmOrderIdentifier = parameters["pnm_order_identifier"]; String siteOrderIdentifier = parameters["site_order_identifier"]; /* This is where you verify the information sent with the * request, validate it within your system, and then return a * response. Here we just accept payments with order identifiers of * "TEST-123" if the request is test mode. */ AuthorizationResponseBuilder auth = new AuthorizationResponseBuilder("2.0"); //auth.SitePaymentIdentifier = siteOrderIdentifier; auth.PnmOrderIdentifier = pnmOrderIdentifier; bool accept = false; if (siteOrderIdentifier != null && siteOrderIdentifier.StartsWith("TEST")) { accept = true; logger.Info("Example authorization " + siteOrderIdentifier + " will be ACCEPTED"); } else { logger.Info("Example authorization " + siteOrderIdentifier + " will be DECLINED"); } if (accept && validSignature) { auth.AcceptPayment = true; /* You can set custom receipt text here (if you want) - if you * don't want custom text, you can omit this */ auth.Receipt = "Thank you for your order!"; auth.Memo = DateTime.Now.ToString(); } else { auth.AcceptPayment = false; auth.Receipt = "Declined"; auth.Memo = "Invalid payment: " + siteOrderIdentifier; } response.ContentType = "application/xml"; auth.Build().Save(response.Output); response.Output.Flush(); logger.Debug("End handleAuthorizationRequest"); }
public void ProcessRequest(HttpContext context) { stopWatch.Start(); logger.Info("Incoming request begin."); string req = context.Request.CurrentExecutionFilePath; try { if (req.Equals("/authorize")) { IAuthorizationHandler handler = new ExampleAuthorizationHandler(); handler.HandleAuthorizationRequest(context.Request.QueryString, context.Response); } else if (req.Equals("/confirm")) { string signature = SignatureUtils.Signature(context.Request.QueryString, Constants.SECRET); if (signature.Equals(context.Request.QueryString["signature"])) { IConfirmationHandler handler = new ExampleConfirmationHandler(); handler.HandleConfirmationRequest(context.Request.QueryString, context.Response); } else { /** * InvalidSignatureException * Invalid Signature is a special case of exception that throws an HTTP Error. With the * exception of Invalid Signature and Internal Server errors, it is expected that the callback * response be properly formatted XML per the PayNearMe specification. * * This is a security exception and may highlight a configuration problem (wrong secret or * siteIdentifier) OR it may highlight a possible payment injection from a source other than * PayNearMe. You may choose to notify your IT department when this error class is raised. * PayNearMe strongly recommends that your callback listeners be whitelisted to ONLY allow * traffic from PayNearMe IP addresses. * * When this class of error is raised in a production environment you may choose to not respond * to PayNearMe, which will trigger a timeout exception, leading to PayNearMe to retry the * callbacks up to 40 times. If the error persists, callbacks will be suspended. * * In development environment this default message will aid with debugging. */ logger.Warn("Invalid signature for /confirm"); logger.Warn(" Got: " + context.Request.QueryString["signature"] + ", expected: " + signature); throw new RequestException("Invalid signature for /confirm", 400); } } else { throw new RequestException("Callback request not found!", 404); } } catch (RequestException e) { /** * Internal Server Error * Internal Server Error is a special case of exception that throws an HTTP Error. With the exception * of Invalid Signature and Internal Server errors, it is expected that the callback response be * properly formatted XML per the PayNearMe specification. * * When this class of error is raised in a production environment you may choose to not respond to * PayNearMe, which will trigger a timeout exception, leading to PayNearMe to retry the callbacks up * to 40 times. If the error persists, callbacks will be suspended. * * This error may highlight a server outage in your infrastructure. You may choose to notify your IT * department when this error class is raised. */ context.Response.ContentType = "text/plain"; context.Response.StatusCode = e.StatusCode; context.Response.Output.WriteLine(e.Message); context.Response.Output.Flush(); } stopWatch.Stop(); logger.Info("Request " + req + " handled in " + stopWatch.ElapsedMilliseconds + "ms"); if (stopWatch.Elapsed.Seconds >= 6) { logger.Warn("Request was longer than 6 seconds!"); } logger.Info("End Incoming Request."); }