Background:
I'm creating my first Authorize.net Accept Hosted solution. The plan is to use the merchant's custom PHP cart to collect the shipping, billing address then present the hosted form to collect payment. Many of the customers will be 'guest' customers without customer profiles generated in the PHP cart.
I have successfully created an XML token request using CURL and used the return token to request the payment form and populate an iframe.
The Problem:
We'd like to pass the billing/shipping info entered into the cart to Auth.net so the customer does not need to re-enter the information. The documentation/examples I have been able to find require use of the SDK to create a customer profile in order to do this.
Is there an easier way?
My questions:
Can we pass the shipping / billing in the token request?
Can we pass the shipping / billing in the form request?
Any other suggestions on how to pass this billing / shipping info without creating a separate customer profile transaction?
If we have to create a customer profile for each transaction, can we create a customer profile using XML/CURL without incorporating the entire SDK?
Thanks in advance for your help.
Yes, you can pass both billing and shipping address infomation to the token reques, which will then be pre-populated in the form :
<getHostedPaymentPageRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
<merchantAuthentication>
<name>YOUR_LOGIN_ID</name>
<transactionKey>YOUR_TRANSACTION_KEY</transactionKey>
</merchantAuthentication>
<transactionRequest>
<transactionType>authCaptureTransaction</transactionType>
<amount>20.00</amount>
<billTo>
<firstName>Ellen</firstName>
<lastName>Johnson</lastName>
<company>Souveniropolis</company>
<address>14 Main Street</address>
<city>Pecan Springs</city>
<state>TX</state>
<zip>44628</zip>
<country>USA</country>
</billTo>
<shipTo>
<firstName>China</firstName>
<lastName>Bayles</lastName>
<company>Thyme for Tea</company>
<address>12 Main Street</address>
<city>Pecan Springs</city>
<state>TX</state>
<zip>44628</zip>
<country>USA</country>
</shipTo>
</transactionRequest>
<hostedPaymentSettings>
<setting>
<settingName>hostedPaymentBillingAddressOptions</settingName>
<settingValue>{"show": true, "required":true}</settingValue>
</setting>
<setting>
<settingName>hostedPaymentButtonOptions</settingName>
<settingValue>{"text": "Pay"}</settingValue>
</setting>
<setting>
<settingName>hostedPaymentReturnOptions</settingName>
<settingValue>{"url":"https://www.mystore.com/good","urlText":"Continue","cancelUrl":"https://www.mystore.com/cancel","cancelUrlText":"Cancel"}</settingValue>
</setting>
<setting>
<settingName>hostedPaymentShippingAddressOptions</settingName>
<settingValue>{"show": true, "required":true}</settingValue>
</setting>
</hostedPaymentSettings>
</getHostedPaymentPageRequest>
Yes, you can also create a customer profile using XML/CURL without incorporating the entire SDK.
Related
getHostedPaymentPageRequest only provides two types of transaction to generate a token for the form using the following XML.
Two transaction type:
authCaptureTransaction
authOnlyTransaction
<getHostedPaymentPageRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
<merchantAuthentication>
<name>5KP3u95bQpv</name>
<transactionKey>346HZ32z3fP4hTG2</transactionKey>
</merchantAuthentication>
<transactionRequest>
<transactionType>authCaptureTransaction</transactionType>
<amount>20.00</amount>
<profile>
<customerProfileId>123456789</customerProfileId>
</profile>
<customer>
<email>ellen#mail.com</email>
</customer>
<billTo>
<firstName>Ellen</firstName>
<lastName>Johnson</lastName>
<company>Souveniropolis</company>
<address>14 Main Street</address>
<city>Pecan Springs</city>
<state>TX</state>
<zip>44628</zip>
<country>USA</country>
</billTo>
</transactionRequest>
<hostedPaymentSettings>
<setting>
<settingName>hostedPaymentReturnOptions</settingName>
<settingValue>{"showReceipt": true, "url": "https://url-when-continue-button-clicked/receipt", "urlText": "Continue", "cancelUrl": "https://url-when-cancel-button-clicked.com/cancel", "cancelUrlText": "Cancel"}</settingValue>
</setting>
<setting>
<settingName>hostedPaymentButtonOptions</settingName>
<settingValue>{"text": "Pay"}</settingValue>
</setting>
<setting>
<settingName>hostedPaymentStyleOptions</settingName>
<settingValue>{"bgColor": "blue"}</settingValue>
</setting>
<setting>
<settingName>hostedPaymentPaymentOptions</settingName>
<settingValue>{"cardCodeRequired": false, "showCreditCard": true, "showBankAccount": true}</settingValue>
</setting>
<setting>
<settingName>hostedPaymentSecurityOptions</settingName>
<settingValue>{"captcha": false}</settingValue>
</setting>
<setting>
<settingName>hostedPaymentShippingAddressOptions</settingName>
<settingValue>{"show": false, "required": false}</settingValue>
</setting>
<setting>
<settingName>hostedPaymentBillingAddressOptions</settingName>
<settingValue>{"show": true, "required":false}</settingValue>
</setting>
<setting>
<settingName>hostedPaymentCustomerOptions</settingName>
<settingValue>{"showEmail": false, "requiredEmail": false, "addPaymentProfile": true}</settingValue>
</setting>
<setting>
<settingName>hostedPaymentOrderOptions</settingName>
<settingValue>{"show": true, "merchantName": "G and S Questions Inc."}</settingValue>
</setting>
<setting>
<settingName>hostedPaymentIFrameCommunicatorUrl</settingName>
<settingValue>{"url": "https://url-contianing-iframe"}</settingValue>
</setting>
</hostedPaymentSettings>
</getHostedPaymentPageRequest>
How should I modify the XML so that I can get the form for recurring billing? As I did not find any implementation example in accept hosted to get a valid form token for recurring billing. There was not mention of recurring billing the accept hosted documentation.
Also, I am using the redirect method and not the iframe one to display the form which does not return any response as well.
There is no one form for creating a subscription through the hosted form. Fortunately someone already posted how to do this on their forum which I will repost here:
If you are trying to use the Accept hosted forms for creating a
subscription, you actually wouldn't use the hosted payment page,
described here.
The correct workflow is, using the API, make a request for a customer
profile: createCustomerProfileRequest. All you need is their email
address.
After getting the profile id from that call, you make a request for a
token for the accept hosted add profile form. Documentation for
this form and others is here. I didn't even realize these forms
existed. It's hard to find them in google even if you know what you're
looking for.
You need the customer profile id to get the token for the "add payment
profile" form.
You handle the response to this form client-side since you are getting
the response from the IFrameCommunicator page you set up (it works the
same for the payment form or these customer profile type forms).
Here's a sample.
I then called server-side code to create the subscription with the api
- I pass it the customer profile id because honestly I don't know if the form returns the newly created payment profile id. If you have the
customer profile id, you can retrieve any existing payment profiles.
So, using just the customer profile id, I make a call to get the
payment profile id - getCustomerProfileRequest. That call returns
all sorts of stuff including the payment profiles. I just grab the
first one. Now with the customer profile id and the payment profile
id, I can create a subscription - ARBCreateSubscriptionRequest.
There are samples out there to help you form the subscription
properly.
Final note: if you are testing this in the sandbox, you will need to
put a 20 second delay between obtaining a payment profile id and
obtaining a subscription using the api. The sandbox does not have the
resources to handle these transactions real time. Figuring that out
cost me several hours. You can read through this post to confirm, and
though it's older, it is still true:
https://community.developer.authorize.net/t5/Integration-and-Testing/E00040-when-Creating-Subscription-from-Customer-Profile/m-p/59597#M34176
I just created tenant with name mycompany.com. Within this tenant, I registered Service Provider with name SP.
After integrating my application with WSO2, the apps will create SAML Authn request
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:AuthnRequest AssertionConsumerServiceURL="https://localhost:8443/myapp/auth/sso"
Destination="https://localhost:9443/samlsso"
ForceAuthn="false" ID="a2i70af753i64cce4ehj977h3h9085h"
IsPassive="false" IssueInstant="2016-03-30T02:51:12.083Z"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">SP#mycompany.com</saml2:Issuer>
<saml2p:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" SPNameQualifier="SP"/>
<saml2p:RequestedAuthnContext Comparison="exact">
<saml2:AuthnContextClassRef xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2p:RequestedAuthnContext>
</saml2p:AuthnRequest>
It will redirect to WSO2 login page with this URL:
https://localhost:9443/authenticationendpoint/login.do?commonAuthCallerPath=%2Fsamlsso&forceAuth=false&passiveAuth=false&tenantDomain=mycompany.com&sessionDataKey=22e974a4-1a42-4670-82f5-3538828d7d03&relyingParty=SP%40mycompany.com&type=samlsso&sp=SP&isSaaSApp=false&authenticators=GoogleOIDCAuthenticator%3AGoogle%3BFacebookAuthenticator%3AFB%3BSAMLSSOAuthenticator%3AADFS%3BBasicAuthenticator%3ALOCAL
I am wondering why I need to passing tenant domain name as part of username.
i.e:
Username: user#mycompany.com
Passwword: secret
Can we configure WSO2 such that it takes the domain name from the URL parameter instead of appending it to the username
Username is used in the same format throughtout all the cases. So, tenant domain should be there with username.
If you don't want to append tenant domain to the username, you can use tenant dropdown feature in the authentication endpoint as described in 'Loading tenants into the dropdown in the login page of the authentication endpoint web application' section of [1]
[1] https://docs.wso2.com/display/IS510/Customizing+the+Authentication+Endpoint
If you have single tenant better you don't want use tenant like above. Please use WSO2 IS without tenant. So you can use only username and password.
I am using Spring 4, with Spring Security 4 to secure web-services. A normal web-service worked fine without security. My secured web-services also seemed to work great working locally and with unit testing.
We are using the SiteMinder example, which means we have authentication happenind from a remote authority. This delivers a token to the browser when we login. We pass the authentication token with a request header, and this is pulled from customerUserDetailsService. That class and methods pull the token from the header, authenticates the user against that remote authority, and we get a username. From that username, we make a DAO call to our database to get the User Details and their Roles, which in the Spring Security Context uses the roles to grant authority. This is all working fine, and we get an authenticated user and we have thier roles/grantedAuthorities.
So, as previously stated, we are now just securing web-services with spring-security.xml to secure the web-services based on the role of the user. Again, this all seemed to work fine with unit testing. We had a token for a user who did not have access to web-sites and we correctly got back a 403 error. When we used a token for a user who did have the right role, was able to execute the web-service.
Now I am trying to deploy this into a new environment, and I am not having much luck.
So, I have a spring-security.xml that looks like:
<http use-expressions="true" auto-config="false" entry-point-ref="http403EntryPoint">
<!-- Additional http configuration omitted -->
<intercept-url pattern="/records/authorizedRecords" access="hasRole('portalUser')" />
<intercept-url pattern="/records/myCode" access="hasRole('portalUser')" />
<intercept-url pattern="/users/email" access="hasRole('appAdmin')" />
<custom-filter position="PRE_AUTH_FILTER" ref="openAmFilter" />
</http>
<beans:bean id="openAmFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<beans:property name="principalRequestHeader" value="openam_token"/>
<beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>
<beans:bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<beans:property name="preAuthenticatedUserDetailsService">
<beans:bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<beans:property name="userDetailsService" ref="customUserDetailsService"/>
</beans:bean>
</beans:property>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="preauthAuthProvider" />
</authentication-manager>
<beans:bean id="customUserDetailsService" class="com.agmednet.server.security.CustomUserDetailsService"></beans:bean>
<beans:bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint">
When we tried access to:
<intercept-url pattern="/users/email/*" access="hasRole('appAdmin')" />
this did not seem to match:
/rest/users/email/myemail#someemail.com
so I changed it to:
<intercept-url pattern="/rest/users/email/*" access="hasRole('appAdmin')" />
And I get this from the log.
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/rest/trials/integratedtrials'; against '/rest/users/email/*'
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Public object - authentication not attempted
DEBUG: org.springframework.security.web.FilterChainProxy - /rest/trials/integratedTrials reached end of additional filter chain; proceeding with original chain
DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
At this point, I know we have an authenticated user, the username, and the roles are listed right there in the logs. We seem to find a matching URL in the spring-security.xml, the URL matches, the roles match, and now I feel we should be executing the logic behind the web-service, but I get an error message:
Apache Tomcat/8.0.30 - Error report
/services/rest/users/email/myemail#someemail.com
The requested resource is not available.
I am absolutely floored here .... unsecured web-services work great. I have to be missing something? Is it with the word "rest" in the URL? Web-services have always worked when they were unsecured. I added security and add unit tests to test this all out, and now I am unsure of what happened?
The problem is that I am an idiot!!!!
In the /WEB-INF/web.xml file I had this defined:
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
I suppose that is why when I call any RESTful web-services with:
/rest/users/email/myemail#someemail.com
it doesn't work.
But when I use:
/api/users/email/myemail#someemail.com
now it works.
Conclusion: I am an idiot!!!
Sitecore ItemWebApi Gurus,
Why am I getting a response of "Access to site is not granted" every time I attempt to make a Sitecore ItemWebApi request?
Here are the security settings in my Sitecore.ItemWebApi.config
<site name="website">
<patch:attribute name="itemwebapi.mode">StandardSecurity</patch:attribute>
<patch:attribute name="itemwebapi.access">ReadOnly</patch:attribute>
<patch:attribute name="itemwebapi.allowanonymousaccess">false</patch:attribute>
</site>
</sites>
Here's how I'm setting up my ItemWebApi request (please note that I have used a fake username, password, and GUID for the purpose of stack overflow):
var client = new WebClient();
var n = new NameValueCollection();
n["X-Scitemwebapi-Username"] = "extranet\\Sample_Username";
n["X-Scitemwebapi-Password"] = "SamplePassword";
client.Headers.Add(n);
var result = client.DownloadString(
"http://localhost:11111/-/item/v1/?sc_itemid={11111111-1111-1111-1111-111111111111}&scope=c");
The response I get back from my request is always:
Access to site is not granted
I'm using sitecore 7.1.
Turns out I was using the wrong password for the user. The code above in my question is perfectly valid and will return a json response containing the desired information about a sitecore item.
I'd like to also add that you need to verify that the sitecore user which you are trying to authenticate with has been "enabled" in sitecore. I had added a user for my Item Web Api through a sitecore package and wasn't aware that when you do that, sitecore by default disables the user. You actually have to manually "enable" the user before it is active.
I'm having serious problems with creating a Web service in Visual Studio 2010 (Framework 4).
Anyway, I have to use a Oracle membership provider (I have installed "Oracle Providers for ASP.NET 4 11.2.0.2.0', which modifies the framework's machine.config), but I can not connect to the membership.
My code in web.config is as follows:
<configuration>
<connectionStrings>
<remove name="OraAspNetConString"></remove>
<add name="OraAspNetConString" connectionString="User Id=USUARIO;Password=PASSWORD;Data Source=DATABASENAME;" providerName="Oracle.DataAcces.Client"/>
</connectionStrings>
<system.web>
<membership defaultProvider="OracleMembershipProvider" userIsOnlineTimeWindow="30"/>
<roleManager defaultProvider="OracleRoleProvider" enabled="true" cacheRolesInCookie="true" cookieName=".ASPROLES" cookieTimeout="30" cookiePath="/" cookieRequireSSL="false" cookieSlidingExpiration="true" cookieProtection="All"/>
<authentication mode="None"/>
<authorization>
<allow users="*"/>
</authorization>
I also added the reference 'System.Web.ApplicationServices' to my project.
To test the connection to the membership of Oracle I have put this code in one of the OperationContract that has my web service:
MembershipUserCollection userC = Membership.GetAllUsers();
sample.StringValue += " - " + userC.Count;
bool resp = Membership.ValidateUser(id, id2);
The obtained MembershipUserCollection always appears without users. UserC.Count always equals zero.
The parameters 'id' and 'id2', username and password respectively, are used to validate (that is a poor use, I know) but always returns false.
Anybody can help me with this?
Thanks a lot.
PD: Authentication mode is 'None', I've tried with 'Forms' and still not working.
Problem solved.
I needed to put the name of the application (applicationName) on the label of the membership and role manager providers (in the file machine.config).
:-)