ServiceNow Redirect URL trimmed upto "&" character - single-sign-on

My Web application redirects to a ServiceNow app and uses SSO to login. I want the user to be redirected to certain content on the ServiceNow platform.
Redirect URL: app?sys_kb_id=d34cecb01bdcd0102fsw&id=kb_article_view&sysparam_rank=1 &sysparam_tsqueryId=37ac2ea11b6689d4db49f2
The problem I am facing is that the redirect URL gets trimmed to the first parameter. This is because of the workflow that has been used and the usage of &.
The workflow we use in ServiceNow is as follows,
logout --> login with sso --> auth redirect
This workflow is important because the clients use the web application on shared hardware. To prevent cross-user access we logout the current user every time the ServiceNow application is opened.
Logout Request
https://example.service-now.com/logout.do?glide_sso_id=<sso-id>&logout_first=true&sysparm_goto_url=%2Flogin_with_sso.do%3Fglide_sso_id%3D<sso-id>%26login_redirect_uri%3Dapp%3Fsys_kb_id%3Dd34cecb01bdcb0102f09986a23shak90%26id%3Dkb_article_view%26sysparm_rank%3D1%26sysparm_tsqueryId%3D37ac2ea11b6689d4db49f2ff034jls72
Payload:{
sysparm_goto_url=%2Flogin_with_sso.do%3Fglide_sso_id%3D<sso-id>%26login_redirect_uri%3Dmyhr%3Fsys_kb_id%3Dd34cecb01bdcb0102f09986a23shak90%26id%3Dkb_article_view%26sysparm_rank%3D1%26sysparm_tsqueryId%3D37ac2ea11b6689d4db49f2ff034jls72
}
Login Request
https://example.service-now.com/login_with_sso.do?glide_sso_id=<sso-id>&login_redirect_uri=app?sys_kb_id=d34cecb01bdcb0102f09986a23shak90&id=kb_article_view&sysparm_rank=1&sysparm_tsqueryId=37ac2ea11b6689d4db49f2ff034jls72
Payload: {
login_redirect_uri=app?sys_kb_id=d34cecb01bdcb0102f09986a23shak90&id=kb_article_view&sysparm_rank=1&sysparm_tsqueryId=37ac2ea11b6689d4db49f2ff034jls72
}
The login API parses the redirect URL, this causes the encoded URL characters to be decoded.
Because of the "&" character in the redirect URL, the URL breaks into separate query parameters,
requiredRedirectUrl: app?sys_kb_id=d34cecb01bdcb0102f09986a23shak90&id=kb_article_view&sysparm_rank=1&sysparm_tsqueryId=37ac2ea11b6689d4db49f2ff034jls72
actualRedirectUrl: app?sys_kb_id=d34cecb01bdcb0102f09986a23shak90
++ id=kb_article_view
++ sysparm_rank=1
++ sysparm_tsqueryId=37ac2ea11b6689d4db49f2ff034jls72
Because the redirect URL is incomplete, the user comes to the landing page and not to the content page.
RequiredEndUrl: https://example.service-now.com/app?sys_kb_id=d34cecb01bdcb0102f09986a23shak90&id=kb_article_view&sysparm_rank=1&sysparm_tsqueryId=37ac2ea11b6689d4db49f2ff034jls72
ActualEndUrl: https://example.service-now.com/app?sys_kb_id=d34cecb01bdcb0102f09986a23shak90
Is there any way to ensure that the Redirect URL is not decoded by the Login API?
Or is there another method to achieve the requirement.

I found a fix for this. The issue was that the logout API decodes the redirect URL before calling the login API, this causes an issue because the characters like "&" are not escaped.
I encoded the redirect URL twice (Double Encode URL) and then added it to the logout request. With this when URL is decoded initially the characters still remain escaped, and the actual redirect URL is sent to the last API call.
Redirect URL: app?sys_kb_id=d34cecb01bdcb0102f09986a23shak90&id=kb_article_view&sysparm_rank=1&sysparm_tsqueryId=37ac2ea11b6689d4db49f2ff034jls72
Double Encoded URL: app%253Fsys_kb_id%253Dd34cecb01bdcb0102f09986a23shak90%2526id%253Dkb_article_view%2526sysparm_rank%253D1%2526sysparm_tsqueryId%253D37ac2ea11b6689d4db49f2ff034jls72

Related

How can I access the redirected url in postman?

I have a big problem. I'm sending a request on postman. Then, the url is redirected. I can see the redirected url in Postman console. But I can't access it from the test tab. I need to access the redirected url because the token is generated here. I can do the same operation using the regular expression extractor in JMeter. But I can't do it in Postman. How can I do this in postman? Can you help me?
enter image description here
You can turn off redirects on a specific request (toggle Automatically follow redirects):
Then you can access the Location header contents through:
pm.response.headers.get('Location')
Following that, you can hit the redirect URL via sendRequest or saving the URL in a Postman variable and using setNextRequest.

Facebook oauth reply with improperly formatted URL parameter

I am trying to authenticate my Facebook app against a user.
My application provides the following for starting the oauth authorization process:
https://graph.facebook.com/oauth/authorize?state=abc&response_type=code&client_id=292634984182123&redirect_uri=http://dev.foo.com:12020/app/c-rex/authorize-facebook-action/&scope=publish_pages,email&type=user_agent
Then the browser redirects to Facebook, asks for the permissions and redirects to the given redirection URL but with improper URL parameters:
http://dev.foo.com:12020/app/c-rex/authorize-facebook-action/?#state=abc&access_token=wqeqeqBAJmOBc25oYf64IaJBO8Y7k0pOgfo3q3PzoystyqvGPFeve5F8RxZCWtAVUyZB14YaWaZC4escFL69UxcZCHZBI2riqx88rUdKFx7riLPY83D1uY1Qtf9LJfZBuC1nv7sJH1BmIOXV0ZAP94jiaXV5M5tNU99lucTAZDZD&expires_in=6078
As you can see the query string is empty and instead the query strings after the '#' as URL fragment. It looks pretty weird...The URL would be correct if it would not contain the hashmark. Since fragment is irrelevant for the server I can not pick up the fragment from the URL inside my code.
Is this a Facebook bug?
https://developers.facebook.com/docs/apps/changelog
[Oauth Access Token] Format - The response format of https://www.facebook.com/v2.3/oauth/access_token returned when you exchange a code for an access_token now return valid JSON instead of being URL encoded. The new format of this response is {"access_token": {TOKEN}, "token_type":{TYPE}, "expires_in":{TIME}}. We made this update to be compliant with section 5.1 of RFC 6749.

SoundCloud API: redirect url

Consider this example for authentication from PHP at https://developers.soundcloud.com/docs/api/guide#authentication seem to suggest you can pass a redirect url as a parameter when you flow a user throught the authentication process:
require_once 'Services/Soundcloud.php';
// create client object with app credentials
$client = new Services_Soundcloud(
'CLIENT_ID', 'CLIENT_SECRET', 'REDIRECT_URL');
// redirect user to authorize URL
header("Location: " . $client->getAuthorizeUrl());
Note the 'REDIRECT_URL' argument in the call to the constructor.
That seems to suggest I can pass an arbitrary redirect url as a parameter, just like you can do with Twitter (the API is quite similar).
However, if I pass an url that does not match the unique redirect url configured for the application, I get an error when the user is redirected to my url:
error=redirect_uri_mismatch&error_description=The+redirection+URI+provided+does+not+match+a+pre-registered+value.
So, what is that parameter supposed to be for, if the only valid value is the redirect url configured for the application?
And how are you supposed to handle authentication if the user can only be redirected to a single fixed url after authentication?? That makes the API completely unusable. When you have a user login into any API (e.g. Twitter or Facebook), you need them to be returned to the page from which they clicked the link to log in, and it is a ridiculous restriction that that url be unique. No other social network api that I've ever seen has this restriction.
Is SoundCloud API really so flawed or am I missing something?
I got an answer from Glen Scott, the author of the php-soundcloud library (a pretty decent wrapper around this terrible API) who provides a workaround. It's painful as it involves an additional redirect but it's all the API allows.
https://github.com/mptre/php-soundcloud/issues/36
I quote:
The API does not allow an arbitrary URL. As you noted, this is unlike
most other oAuth-backed social network API's. The workaround I can
recommend is using the state parameter to pass back your return URL.
You can do this when generating the authorization URL like this:
$client->getAuthorizeUrl(
array(
'state' => 'http://example.com/return'
) You'll get the state parameter added to the static redirect URL. For example, if you set your redirect URL to
http://example.com/callback then SoundCloud will redirect an
authenticated user to
http://example.com/callback?state=http://example.com/return
Your callback script will need to look for the state GET parameter,
and redirect using it.

Re-post HTML form after OpenAM/OpenSSO authentication

The default process when authenticating user on OpenAM/OpenSSO works with a 302 http redirection, opening OpenAM/OpenSSO authentication formular. The original URL is stored into "goto" parameter, which allows OpenAM/OpenSSO to redirect the user back on orignal URL after correct authentication.
This works well when using HTTP GET method (i.e. when entering URL), but it is not suitable for POST method. For instance, if the session expires while the user posts a HTML form, the data are lost because HTML form inputs are not present in goto parameter.
Do you know it it is possible to configure J2EE Agent in order it re-posts user HTML form after valid authentication ?
Both the Java EE and the Web agents support post data preservation, see the documentation.

Facebook server-side authentication flow: is this the right "code?"

I'm using FB.login on the JS client and want to verify the user's identity on the server. So, the client gets a signedRequest from facebook and sends it to the server. The server splits on the period, and decodes the second part of the signedRequest into a json object.
What should I be using for "code" when I send my server-side request to
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID
&redirect_uri=YOUR_REDIRECT_URI
&client_secret=YOUR_APP_SECRET
&code=CODE_GENERATED_BY_FACEBOOK
My decoded json looks something like:
{"algorithm":"HMAC-SHA256","code":"2.AQCPA_yfx4JHpufjP.3600.1335646800.1-5702286|l11asGeDQTMo3MrMx3SC0PksALj6g","issued_at":1335642445,"user_id":"5232286"}
Is that the code I need? Does it need to be B64 encoded? If this isn't the code, what code should I use?
_
What I've tried:
The request I'm trying to use is:
https://graph.facebook.com/oauth/access_token?client_id=295410083869479&redirect_uri=https://squaredme.appspot.com/facebookredirect&client_secret=44f1TOPSECRETbb8e&code=2.AQCPA_yfx4JHpufjP.3600.1335646800.1-5702286|l11asGeDQTMo3MrMx3SC0PksALj6g
but this returns the error:
{"error":{"message":"Error validating verification code.","type":"OAuthException","code":100}}
I can't tell if this is because I'm using a bad code, or what. Noteably, this is running on my local dev server, and squaredme.appspot.com definitely does NOT resolve to my IP. I don't know if facebook checks that or what - I'm assuming I'd get a better error message. Thanks for any direction!
You are trying to somehow combine the two flows together and that's why things don't work well.
When facebook POSTs into the iframe with your app url and a signed request there are two options, the easy one being that the user is already authenticated and then the signed request will have all the necessary data (including a signed request), then you just load the canvas page and use the JS SDK to get an access token there as well, but in this case there's no need to use the FB.login (since it opens a popup and will automatically close it), you can use the FB.getLoginStatus method which won't annoy the user.
If the user is not authenticated then the sign request will be missing the things you need to use the graph api.
You then redirect the user to the auth dialog, and since you are loaded in an iframe you'll need to return a html response which redirects the parent window using javascript, like:
top.location.href = "AUTH_DIALOG_URL";
When the use is done (accepted or rejected the app) he will be redirected to the "redirect_uri" you added as a parameter to the auth dialog.
If the user accepted your app then you'll be getting the "code" parameter in the query string.
You then take the code, exchange it with an access token as you posted in your question, and then redirect the user back to "apps.facebook.com/YOUR_APP".
When the page then loads the user is already authenticated and you'll be getting a full signed request.
I hope this clarifies things for you, recheck the Server-Side flow it pretty much covers it all.
I also had some trouble with that, then I found the solution here in StackOverflow.
There are two kinds of "code" provided by facebook. One comes inside the signedRequest in the cookie generated by the client-side flow. The Facebook's JS SDK handles this codes and get a access token without telling us anything.
The other type of code comes attached as a query to your redirect URI (http://www.yoururl.com/index.php?code=AAAgyiaus...), when you navigate to OAuth URL (server-side flow). With this code, you go to a Token URL and get your access token.
When you are using the server-side flow, you need to indicate a redirect URI both in the OAuth URL AND in the Token URL, and they have to be exactly the same, so a missing slash or a query string can be a lot of problem.
The codes are different from each other. When you use the both things together, appears to be impossible to get a access token using the code that was inside the cookie's signedRequest.
BUT, it is not. The magic is: the code from signedRequest is associated with NO URI, so as long as the redirect_uri is a mandatory field, all you have to do is to pass it blank when you navigate to the Token URL.
So the final solution is: grab the signedRequest from the cookie, parse it in your server to obtain the code, then read the Token URL:
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID
&redirect_uri=&client_secret=YOUR_APP_SECRET
&code=CODE_INSIDE_THE_SIGNED_REQUEST
It looks like a hack, so I don't know how long it's gonna work, but it's working right now.