My company is working on a new SharePoint site, which will use Forms Based Authentication to allow our customers to log into the site for subscriber specific content (downloads, license info, etc).
All these customers are located within our CRM, NetSuite, which is where we want our customer care teams to update a customers information and assign them to FBA roles (the roles are already added to Groups in SharePoint).
To do this, I'm looking to create SOAP XML files, that can be used by NetSuite's own development language, SuiteScript, which would send the SOAP request, and the process the response.
For example: Using soapUI I'm constructing the following XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dir="http://schemas.microsoft.com/sharepoint/soap/directory/">
<soapenv:Header/>
<soapenv:Body>
<dir:GetUserInfo>
<dir:userLoginName>myUserName</dir:userLoginName>
</dir:GetUserInfo>
</soapenv:Body>
</soapenv:Envelope>
The problem is that my XML response, when executing this XML using soapUI, is 403 FORBIDDEN - the Raw response is:
HTTP/1.1 403 Forbidden
Cache-Control: private, max-age=0
Server: Microsoft-IIS/7.5
SPRequestGuid: 36264ce4-9702-44bb-9693-23852a5e0c99
X-SharePointHealthScore: 1
X-Forms_Based_Auth_Required: http://mySPserver/_layouts/login.aspxReturnUrl=/_layouts/Error.aspx&Source=%2f_vti_bin%2fusergroup.asmx
X-Forms_Based_Auth_Return_Url: http://ec2-devmoss1/_layouts/Error.aspx
X-MSDAVEXT_Error: 917656; Access denied. Before opening files in this location, you must first browse to the web site and select the option to login automatically.
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 14.0.0.4762
Date: Tue, 19 Jul 2011 19:25:47 GMT
Content-Length: 13
403 FORBIDDEN
I'm guessing I need to log in somehow using credentials within the XML, but how do I do that? I tried using this in my <soapenv:Header>...
<soapenv:Header>
<h:BasicAuth xmlns:h="http://soap-authentication.org/basic/2001/10/" SOAP-ENV:mustUnderstand="1">
<Name>user</Name>
<Password>password</Password>
</h:BasicAuth>
</soapenv:Header>
but then my Raw response becomes:
HTTP/1.1 400 Bad Request
Cache-Control: private
Server: Microsoft-IIS/7.5
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 14.0.0.4762
Date: Tue, 19 Jul 2011 19:43:12 GMT
Content-Length: 0
Can anyone advise on how to correctly form an XML SOAP call for this, or any, SharePoint web service method, or point me to an article/question (with answer) that explains it? I tried googling and looking through stackoverflow (of course ), but I just cannot find the information/solution I need.
(sorry for the really long question)
Kevin
In the warm, fuzzy .Net world...
Accessing webservices on a SharePoint site using FBA takes a little extra work.
In .Net, it's pretty simple. In fact, there's a MSDN article with code samples and all on precisely how to do that. In summary, you first call the Login method on Authentication.asmx, and use the returned cookie in all future web service requests.
Outside .Net
One dark and stormy night, I ventured out into the non-Microsoft world. No-man's land. Without the .Net generated web service proxies, we were rolling our own SOAP messages to communicate with SharePoint webservices.
Where's my cookie??
Without the .Net proxy, you can't use CookieContainer as the MSDN article suggests. Authentication.asmx's description for Login shows the following SOAP response:
The response XML simply contains the authentication cookie's name. Where did the actual cookie go? GIMME MY COOKIE!!!
Getting the cookie
It turns out the cookie is sent in the SOAP header. If login is successful, the response's SOAP header will look something like this:
The Set-Cookie field above gives us the FBA cookie called .ASPXAUTH, with value 987A98.......
Using the cookie
To use the cookie for web service requests, we need to include it in the SOAP request header by adding a Cookie field:
You can include multiple cookies by separating the name/value pairs with semi-colons. Once the .ASPXAUTH cookie is set, you can send the request and a response should be returned as normal.
No-man's land behind ISA lines
SharePoint sites behind an ISA server with Forms authentication can be handled similarly. The difference is that we have to get the authentication cookies from the ISA server instead of SharePoint. That can be done by POSTing to the /CookieAuth.dll?Logon url. I won't go over the details, but it shouldn't be hard to figure out the appropriate url and querystring to use.
I found this again after the original blog disappeared then reappeared. Added for posterity here in case the blog goes away.
New blog location.
Author Bio
Related
I use Postman 4.4.1 in Chrome 51.0.2704.63.I have set up a web project with Tomcat6, the web.xml like:
<web-app>
<display-name>Archetype Created Web Application</display-name>
<security-constraint>
<web-resource-collection>
<web-resource-name>
My App
</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>tomcat</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>DIGEST</auth-method> <!-- DIGEST here -->
<realm-name>My Realm</realm-name>
</login-config>
</web-app>
When I access http://localhost:8080/simple-web/ use my local browser, a window pops up to let me input username and password. After fill, it works well.
When I use Postman, I input the username and password in Authorization Page, and choose the Type with Digest Auth.It always shows to me 401 Unauthrized.
I can see the Headers:
Cache-Control →no-cache
Content-Length →954
Content-Type →text/html;charset=utf-8
Date →Fri, 29 Jul 2016 10:26:20 GMT
Expires →Thu, 01 Jan 1970 08:00:00 CST
Pragma →No-cache
Server →Apache-Coyote/1.1
WWW-Authenticate →Digest realm="My Realm", qop="auth", nonce="dcb71e7d6766f85c3f233b7b74e42423", opaque="4894d1ece1380278a451585e9b548e21"
Can someone knows the reason and how to fix it?
From the beginning I have used a two step process with Digest Authentication build the request build the request from Firebug and send it and get the 401 copy the nonce and sometimes the opaque into the digest fields and resend for success.
Discussions on the forums lead me to believe that it is still an issue. Am using 5.1.2 Windows App.
I model my initial request on what I see in Firebug when I paste the url and get back the expected response.
Late answer but posting it here as my team struggled with this as well, while it's just a matter of carefully reading the documentation.
According to the Postman documentation,
(..) server responds with a few details, including a number that can be used only once (nonce), a realm value, and a 401 unauthorized response. You then send back an encrypted array of data including username and password combined with the data received from the server in the first request.
As it is already visible in the output you have provided, you are indeed provided with nonce, qop and opaque values. Hence, after the initial request that gets a 401 response, you would create another one, which would be almost the same as the previous one, just with the additional nonce, qop and opaque values set.
I’m developing an Android App and a Web Service that communicate. My Web Service is in WEB API 2 with token bearer authentication.
My problem is that when I send too many requests (~20 request in 15 seconds) to my Web Service from my Android App, the WS response with
“401” : “Authorization has been denied for this request”
This happen ONLY on the production server (Amen hoster) AND from the Android Device. For example, if I try with Postman, everything works fine. So it’s related to my production server and/or my android app request.
The code for access to the Web Service
URL obj = new URL(SERVEUR_URL + url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Authorization", "Bearer " + token);
con.setRequestProperty("Content-Type", "application/json");
int responseCode = con.getResponseCode();
String responseMessage = con.getResponseMessage();
The authentication provider on my Web Service is the default one. No modifications.
The request from my Android App (not work every time)
GET http://api.xxxx.com/api/Weesps/GetAvailableWeesps HTTP/1.1
Authorization: Bearer XXXX
Content-Type: application/json
User-Agent: Dalvik/2.1.0 (Linux; U; Android 6.0; Google Nexus 5X - 6.0.0 - API 23 - 1080x1920 Build/MRA58K)
Host: api.xxxx.com
Connection: Keep-Alive
Accept-Encoding: gzip
The request from Postman (work every time)
GET http://api.xxxx.com/api/Weesps/GetAvailableWeesps HTTP/1.1
Host: api.xxxx.com
Connection: keep-alive
Authorization: Bearer XXXX
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
Postman-Token: bca55154-775d-9709-7a8b-4793393890ad
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: dadaproaffinity=14ff51cc869a14d3552485cb4ceee1faa1be7165cc5d4b0e2b19370f11afcbea
What I have tried:
Reproduce this error in local : it works fine on local server (web and SQL servers) from android app or from Postman
I check that the token was sent correctly in every requests
The request from Android is the same every time
Tried to add missing header to my android app request
I spend two days on this problem and read many stackoverflow posts but no one helps me.
Thanks for your help.
UPDATE 1 :
With Fiddler I saw that in GET request from Postman, they were a Cookie header. This cookie is sent when we ask for a bearer token.
Example of token response from the server
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 691
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.5
Set-Cookie: .AspNet.Cookies=XXXX; path=/; HttpOnly
X-Powered-By: ASP.NET
X-Powered-By: ARR/2.5
Date: Tue, 31 May 2016 16:55:39 GMT
{"access_token":"XXXX","token_type":"bearer","expires_in":1209599,"userName":"Foo",".issued":"Tue, 31 May 2016 16:55:40 GMT",".expires":"Tue, 14 Jun 2016 16:55:40 GMT"}
Fiddler and Postman saved this cookie and they automatically put it in requests to API (example on the “The request from Postman” code block). When I remove the cookie from the Postman GET request, it doesn’t work (just like my android app).
Now, the question is: why WEB API 2 send a cookie instead of only using the token ? And why the token work great in the first requests and don’t work properly for the following requests ?
According to ASP.NET WebAPI2 flow you can see on the bottom of that page, it seems your requests are always authenticated but sometimes fail to get authorized.
So imo, the AuthorizationFilter[Authorize] rejects some of your requests for an unknown reason. What I would suggest is to dump the request your API receives as well as the claims identity attached to the token. Try to see if there is differences between them when you have a successful response and when you have a 401.
That way, you may be able to determine either it is your request that got malformed, if it is the claims identity that is not good or if it is the AuthorizationFilter that refuses you for another reason (like too much queries or else).
Good luck !
UPDATE 1
According to your new input, I think that your Web API is configured to use both token and cookie authentication.
What I see here is you have two solutions :
1°/ Store the returned cookie in your Android application and use it for next calls. Simplest and fastest way to solve your problem without changing all your API, but you store an authorization cookie : it can leads to security problem (CSRF attacks).
2°/ You can check how your authentication and authorization filters are set to disable cookie authentication and only rely on token authentication : it will hence forces all the requests and your API to only use token and will prevents you from suffering CSRF attacks. More complex because you have to dig into your web API configuration.
Check the following links (sorry, as I don't have enough reputation yet to post more than 2 links per post, you'll find them as text at the end of my answer) :
ASP.net Secure a Web API 2.2[2] : From the chapter "Configuring the Authorization Server" at the bottom
MSDN article on Web API security[3] : More general and technical information about web api security, how to secure it and CRSF attacks
StackOverflow .NET cookie and token authentication[4] : Check David Banister's answer, I think it is exactly what you want to do : Only use token for all your API calls.
StackOverflow Authorize filter and authentication[5] : More information about such mechanisms for your API
And finally
Cookie authentication with web API and 401 codes[6] : Sounds like your actual problem, isn't it ?
I hope it helps you, good luck !
// Links
2: www.asp.net/web-api/overview/security/individual-accounts-in-web-api
3: msdn.microsoft.com/en-us/magazine/dn201748.aspx
4: stackoverflow.com/questions/22568409/mvc-net-cookie-authenticated-system-acessing-a-web-api-with-token-authenticatio
5: stackoverflow.com/questions/21231751/authorize-filter-and-authentication
6: brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/
Finally, I got my answer:
My Web Service send a Cookie named “dadaproaffinity” the first time I ask for a request. This Cookie was automatically put on the following request by Postman but not by Android HttpUrlConnection. So, I just take this Cookie and now I just add this Cookie on every requests with the Token.
But : This cookie is send by IIS, not by my Web Service ! That’s why it works on local but not on the production server. I googled this cookie and there are very few responses about that. The only one that I find in English is :
Technical Cookie of IIS Server hosting the site.
Need to route to the correct server session, in order to keep it active
Does anyone have more information about this IIS Cookie ?
after nog using the backend of our umbraco website for a few months I started developing for our website again. As the website was being used by some people, I decided to use a staging environment.
So I moved all my files and finally got the database also cloned.
But now whenever I try to login to the backend of umbraco (in the live and the staging environment) I get a javascript error in my firebug console:
{"Message":"The user has no umbraco contextid - try logging in","StackTrace":" at Umbraco.Web.Security.WebSecurity.ValidateCurrentUser(HttpContextBase httpContext, Boolean throwExceptions)\r\n at Umbraco.Web.Security.WebSecurity.AuthorizeRequest(HttpContextBase httpContext, Boolean throwExceptions)\r\n at Umbraco.Web.WebServices.UmbracoAuthorizedWebService.AuthorizeRequest(Boolean throwExceptions)\r\n at Umbraco.Web.WebServices.UmbracoAuthorizedWebService.AuthorizeRequest(String app, Boolean throwExceptions)\r\n at umbraco.presentation.webservices.TreeClientService.GetInitAppTreeData(String app, String treeType, Boolean showContextMenu, Boolean isDialog, TreeDialogModes dialogMode, String functionToCall, String nodeKey)","ExceptionType":"System.InvalidOperationException"}
As suggested in other posts, I delete my cookies and try again, but no luck.
I also get some other errors from time to time:
uiKeys is undefined
I uploaded my umbraco/config/lang folder using Binary, but I still get the error sometimes
Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.
I added this to my web.config
<pages enableEventValidation="false" validateRequest="false" viewStateEncryptionMode ="Never" />
and the error seems gone
I also got some error about synthax in the document type declaration at the start of the logout page which I get redirected to
I have been at this for several hours and can't seem to fix it.
Locally loggin in works.
Edit
I just did a fresh install of 6.1.6 and 6.1.5 and tried to logon but I still get the error:
http://staging.mydomaimn.com/umbraco/webservices/TreeClientService.asmx/GetInitAppTreeData 500 Internal server error:
{"Message":"The user has no umbraco contextid - try logging in","StackTrace":" at Umbraco.Web.Security.WebSecurity.ValidateCurrentUser(HttpContextBase httpContext, Boolean throwExceptions)\r\n at Umbraco.Web.Security.WebSecurity.AuthorizeRequest(HttpContextBase httpContext, Boolean throwExceptions)\r\n at Umbraco.Web.WebServices.UmbracoAuthorizedWebService.AuthorizeRequest(Boolean throwExceptions)\r\n at Umbraco.Web.WebServices.UmbracoAuthorizedWebService.AuthorizeRequest(String app, Boolean throwExceptions)\r\n at umbraco.presentation.webservices.TreeClientService.GetInitAppTreeData(String app, String treeType, Boolean showContextMenu, Boolean isDialog, TreeDialogModes dialogMode, String functionToCall, String nodeKey)","ExceptionType":"System.InvalidOperationException"}
This is on a fresh install that never had logins before
Perhaps the problem is with the database setup. My host uses MSSQL 2012 and I have two databases, the first is for the live version which is called 'myloginname' and the second is for the staging which is called 'myloginname_1'.
is the _1 a problem when placing the logon in the database (which I read Umbraco does)?
Edit 2
just looked in my database and Umbraco does create a contextId in the db table 'umbracoUserLogins' but does not create the cookie which should contain the same 'UMB_UCONTEXT'
so this is probably my real problem, what could be causing this?
Edit: some more info on this:
When I look in Fiddler I can see this:
On the 'Raw' tab:
HTTP/1.1 302 Found Cache-Control: private Content-Type: text/html;
charset=utf-8 Location: /umbraco/ Set-Cookie:
ASP.NET_SessionId=zjlqfoxq421wmnpeydcbxv1t; path=/; HttpOnly
Set-Cookie: ASP.NET_SessionId=zjlqfoxq421wmnpeydcbxv1t; path=/;
HttpOnly Set-Cookie: UMB_UCONTEXT=694C3[...a lot of text...]CFDD5EDB;
expires=Tue, 12-Nov-2013 14:07:23 GMT; path=/; HttpOnly Date: Mon, 11
Nov 2013 14:07:23 GMT Content-Length: 126
The cookie tab shows:
Response sent 1318 bytes of Cookie data: Set-Cookie:
UMB_UCONTEXT=694C3[...a lot of text...]D5EDB; expires=Tue, 12-Nov-2013
14:07:23 GMT; path=/; HttpOnly This response did not contain a P3P
Header.
So we can conclude:
the expiration time and date are correct
there is a 302 error, but this seems to be for all cookies and the
other two mentioned are created (I'm confused about this)
perhaps the P3P headers are an issue?
I was able to fix this.
The reason why the UMB_UCONTEXT cookie wasn't created was that I fixed the error
Validation of viewstate MAC failed. If this application is hosted by a
Web Farm or cluster, ensure that configuration specifies the same
validationKey and validation algorithm. AutoGenerate cannot be used in
a cluster.
the wrong way. As How To Fix the: “Validation of viewstate MAC failed” Error (ASP.NET MVC) shows, I needed to create a random machinekey and add it to my web.config
I have a scenario in which a client application sends a POST request to an asp.net page to which the page responds with a json string which I need to consume on the client side.
However, Internet explorer is trying to download the *.aspx page, containing the json string.
What HTTP headers must the response contain to disable the download in Internet Explorer?
Currently, the response HTTP headers are:
Access-Control-Allow-Headers:X-File-Name,X-File-Type,X-File-Size
Access-Control-Allow-Methods:GET,POST,OPTIONS
Access-Control-Allow-Origin:*
Cache-Control:private,private, no-cache
Content-Length:1050
Content-Type:application/json; charset=utf-8
Date:Fri, 12 Jul 2013 08:24:24 GMT
Pragma:no-cache
Server:Microsoft-IIS/7.5
Set-Cookie:ASP.NET_SessionId=qjudp3nct3czltyvc4yxpiri; path=/; HttpOnly
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
It depends on how you are consuming that web service.
If you are consuming it from inside a web page using jQuery, it shouldn't be a problem, Internet Explorer won't force download the file.
If you access the file directly after the POST (redirect to the URL that serves the JSON) and you want to display the JSON as plain text, you must set the Content-Type to text/plain; charset=utf-8
I need to set a cookie before I issue a request to a Web site using Fiddler. How do I do this?
Simple...You need to set a header value, with your request, like so:
Cookie: YourCookieName=YourCookieValue
To do this using the FiddlerScript engine, add the following code into the onBeforeRequest method:
oSession.oRequest["Cookie"] = (oSession.oRequest["Cookie"] + ";YourCookieName=YourCookieValue");
This will preserve any other cookies that have been set.
You need to be more specific about what you're trying to do.
You can edit (or add) an outbound Cookie header to send a cookie to the website. You can do this either manually or via the FiddlerScript engine. But that doesn't "set" the cookie on the client-- it simply sends it to the server. If you want to set a cookie on the client, you either have to use another means, or you can inject a Set-Cookie response header on a previous response from the server, with the value you want to set on the client.
You can also use the Fiddler Composer.
Run Fiddler
Open the Composer Tab on the top.
It's easiest if you can start with another request from your web site. To do this capture a the request you want to modify, then drag it from the UI to the composer tab.
A good explanation is here: http://www.debugtheweb.com/Fiddler/help/composer.asp
Fiddler allows your to resend/rebuild an existing request. There is a Request Builder. While rebuilding in the RAW form, modify your cookies.
This solution is valid for Cookie based authentication:
If you want to test the API/url which have authentication enabled, please try following, i am showing for MVC web API on IIS server. usually there are more than 1 cookie responsible for authorization, so you may need to send more than 1 cookie in header as follows:
User-Agent: Fiddler Host: localhost:51000 content-Type: application/json Cookie : .ASPXAUTH=xxxxx;ASP.NET_SessionId=yyyy;__RequestVerificationToken=zzzz
When running Fiddler as a reverse Proxy you can modify the response headers
via FiddlerScript by adding a line in the OnBeforeResponse method:
static function OnBeforeResponse(oSession: Session) {
// ...
oSession.oResponse["Set-Cookie"] = "sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT";
}
Also check Fiddler docs about Modifying a Request or Response for more info.