Guest User

Untitled

a guest
Feb 26th, 2018
42
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
XML 13.73 KB | None | 0 0
  1. xquery version "3.1";
  2.  
  3. module namespace interceptor="http://haptixgames.com/oauth-interceptor";
  4.  
  5. import module namespace functx="http://www.functx.com";
  6. import module namespace xqjson="http://xqilla.sourceforge.net/lib/xqjson";
  7. import module namespace console="http://exist-db.org/xquery/console";
  8.  
  9. declare namespace http="http://expath.org/ns/http-client";
  10. declare namespace json="http://www.json.org";
  11. declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";
  12.  
  13. declare variable $interceptor:DATA-PATH := '/db/apps/OAuthInterceptor/data';
  14.  
  15. declare function interceptor:authorizationHeader($state)
  16. {
  17.     let $pairs := interceptor:registration-document($state)/request/json
  18.     let $auth-option :=
  19.     try {
  20.         xs:boolean($pairs/pair[@name eq "o"]/item[pair/@name eq "k" and pair eq "u_tba"]/pair[@name eq "v"]/string())
  21.     } catch * {
  22.         false()
  23.     }
  24.    
  25.     return if($auth-option) then
  26.     (
  27.         element header { attribute name { "Authorization" },
  28.             attribute value {
  29.                 "Basic "||util:base64-encode($pairs/pair[@name eq "i"]||":"||$pairs/pair[@name eq "k"])
  30.             }
  31.         }
  32.     )
  33.     else ()
  34. };
  35.  
  36. (:
  37. declare
  38.     %rest:OPTIONS
  39. function interceptor:register-state-options()
  40. {
  41.     <rest:response>
  42.         <http:response status="200">
  43.             <http:header name="Access-Control-Allow-Origin" value="*"/>
  44.             <http:header name="Access-Control-Allow-Methods" value="POST"/>
  45.         </http:response>
  46.     </rest:response>
  47. };
  48. :)
  49.  
  50. declare
  51.     %rest:POST("{$payload}")
  52.     %rest:path("/oauth-interceptor/register-state")
  53.     %rest:consumes("multipart/form-data")
  54.     %rest:produces("application/json")
  55.     %output:media-type("application/json")
  56.     %output:method("json")
  57. function interceptor:register-state($payload as xs:string)
  58. {
  59.     try
  60.     {
  61.         (:let $json := util:base64-decode($payload):)
  62.        
  63.         let $xml := xqjson:parse-json($payload)
  64.        
  65.         let $location :=
  66.             xmldb:store(
  67.                 $interceptor:DATA-PATH,
  68.                 $xml/pair[@name='s']||'.reg',
  69.                 element registration {
  70.                     attribute state { $xml/pair[@name='s'] },
  71.                     element request {
  72.                         attribute timeStamp { util:system-dateTime() },
  73.                         $xml
  74.                     }
  75.                 },
  76.                 'application/xml')
  77.            
  78.         return
  79.         (<rest:response>
  80.             <http:response status="200">
  81.                 <http:header name="Access-Control-Allow-Origin" value="*"/>
  82.             </http:response>
  83.         </rest:response>)
  84.     }
  85.     catch *
  86.     {
  87.         <rest:response>
  88.             <http:response status="500">
  89.                 <http:header name="Access-Control-Allow-Origin" value="*"/>
  90.             </http:response>
  91.         </rest:response>
  92.     }
  93. };
  94.  
  95.  
  96. declare
  97.     %rest:GET
  98.     %rest:path("/oauth-interceptor")
  99.     %rest:query-param("error", "{$error}")
  100.     %rest:query-param("state", "{$state}")
  101.     %rest:query-param("code", "{$code}")
  102. function interceptor:callback($error, $state, $code)
  103. {
  104.     (
  105.         if(not(interceptor:registration-exists($state))) then
  106.         (
  107.             interceptor:insert-error($state,"registration-document-not-found","Unable to find registration record.")
  108.         )
  109.         else if(empty($error)) then
  110.         (
  111.             (: TODO - determine post type u_frm/u_qry :)
  112.            
  113.             let $body := interceptor:build-token-post-from-auth-code($code,$state)
  114.                        
  115.             let $response := httpclient:post(
  116.                 xs:anyURI(interceptor:registration-document($state)/request/json/pair[@name eq "t_u"]),
  117.                 $body,
  118.                 false(),
  119.                 element headers {
  120.                     element header { attribute name { 'Content-Type' }, attribute value { 'application/x-www-form-urlencoded' } },
  121.                     interceptor:authorizationHeader($state)
  122.                 })
  123.                 (: TODO - set content type on u_cnt :)
  124.            
  125.             (: TODO - pick apart response and determine errors :)    
  126.             return
  127.             if(number($response/@statusCode) ne 200) then
  128.             (
  129.                 interceptor:insert-error($state,number($response/@statusCode),"Faulted HTTP response while obtaining access token."),
  130.                 interceptor:insert-error($state, try{xqjson:parse-json(util:base64-decode($response/httpclient:body/text()))}catch*{()},"Transport failure while obtaining access token.")
  131.             )
  132.             else
  133.             (
  134.                 update insert element
  135.                 response {
  136.                     attribute timeStamp { util:system-dateTime() },
  137.                     xqjson:parse-json(util:base64-decode($response/httpclient:body/text()))
  138.                 } into
  139.                 interceptor:registration-document($state)    
  140.             )
  141.         )
  142.         else
  143.         (
  144.             interceptor:insert-error($state,$error,"Failure while obtaining authorization code.")
  145.         ),
  146.         interceptor:clear-secrets($state),
  147.         interceptor:redirection-response($state)
  148.     )
  149. };
  150.  
  151. declare function interceptor:insert-error($state,$error,$description)
  152. {
  153.     if(interceptor:registration-exists($state)) then
  154.     (
  155.         update insert element
  156.             error {
  157.                 attribute timeStamp { util:system-dateTime() },
  158.                 element short { $error },
  159.                 element long { $description }
  160.             } into
  161.             interceptor:registration-document($state)
  162.     )
  163.     else ()
  164. };
  165.  
  166. declare function interceptor:build-token-post-from-auth-code($code,$state)
  167. {
  168.     if(interceptor:registration-exists($state)) then
  169.     (
  170.         let $pairs := interceptor:registration-document($state)/request/json
  171.        
  172.         let $token-request :=
  173.         util:unescape-uri(
  174.                 "code=" || $code || "&#38;" ||
  175.                 "client_id=" || $pairs/pair[@name eq "i"] || "&#38;" ||
  176.                 "client_secret=" || $pairs/pair[@name eq "k"] || "&#38;" ||
  177.                 "redirect_uri=" || $pairs/pair[@name eq "r_u"] || "&#38;" ||
  178.                 string-join(for $field in $pairs/pair[@name eq "t_p"]/item
  179.                     return $field/pair[@name eq "k"] || "=" || $field/pair[@name eq "v"], "&#38;"),
  180.                 "UTF-8")
  181.                
  182.         let $log := console:log($token-request)
  183.                
  184.         return $token-request
  185.     )
  186.     else ()
  187. };
  188.  
  189. declare function interceptor:redirection-response($state)
  190. {
  191.     let $completion-uri :=  "/exist/restxq/oauth-interceptor/complete"
  192.     return
  193.     <rest:response>
  194.         <http:response status="302">
  195.             <http:header
  196.                name="location"
  197.                value="{ $completion-uri || xs:string('?state=') || $state }">
  198.             </http:header>
  199.         </http:response>
  200.     </rest:response>
  201. };
  202.  
  203. declare function interceptor:registration-document($state)
  204. {
  205.     collection($interceptor:DATA-PATH)/registration[@state eq $state]
  206. };
  207.  
  208. declare function interceptor:registration-exists($state)
  209. {
  210.     exists(collection($interceptor:DATA-PATH)/registration[@state eq $state])
  211. };
  212.  
  213. declare function interceptor:clear-secrets($state)
  214. {
  215.     if(interceptor:registration-exists($state)) then
  216.     (
  217.         (: TODO - if u_dbg=true then do not delete secrets :)  
  218.        
  219.         update delete
  220.             interceptor:registration-document($state)
  221.             /request/json/pair[@name = ('s','i','k')]
  222.     )
  223.     else ()
  224. };
  225.  
  226.  
  227. declare
  228.     %rest:GET
  229.     %rest:path("/oauth-interceptor/complete")
  230.     %rest:query-param("state", "{$state}")
  231.     %rest:produces("text/html")
  232.     %output:method("html")
  233. function interceptor:callback($state)
  234. {
  235.     let $errors := interceptor:registration-document($state)/error
  236.     let $back-color := if(empty($errors)) then '#00CCFF' else '#FF0000'
  237.    
  238.     return
  239.     element div {
  240.         attribute style {
  241.             "background: " || $back-color ||"; height: 300px; top: 50%; tranfsorm: translateY(-50%); align-items:center;display:flex;justify-content:center;"
  242.         },
  243.         element div {
  244.             element img {
  245.                 attribute src { "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d2/Oauth_logo.svg/180px-Oauth_logo.svg.png" }
  246.             }
  247.         },
  248.         element div {
  249.             if(empty($errors)) then
  250.             (
  251.                 element p { "Authentication complete." },
  252.                 element p { "You may now return to your application." },
  253.                 element p {
  254.                     attribute style { "color: #FF0000" },
  255.                     "Haptix Games provides this redirect service for testing purposes only.",
  256.                     element br { },
  257.                     "Server-side source code is included with the asset."
  258.                 }
  259.             )
  260.             else
  261.             (
  262.                 element p {
  263.                     attribute style { "color: #FFFFFF" },
  264.                     "Authentication failed!"
  265.                 },
  266.                 for $error at $position in $errors
  267.                 order by $error/@timeStamp ascending
  268.                 return element div { element p { element small { "Exception " || $position || "." } }, element blockquote { element small { $error } } },
  269.                 element p {
  270.                     attribute style { "color: #FFFFFF" },
  271.                     "Return to your application and try again or contact the application's developer."
  272.                 }
  273.             )
  274.         }
  275.     }
  276. };
  277.  
  278.  
  279. declare
  280.     %rest:GET
  281.     %rest:path("/oauth-interceptor/retrieve-response")
  282.     %rest:query-param("state", "{$state}")
  283.     %rest:consumes("multipart/form-data")
  284.     %rest:produces("application/json")
  285.     %output:media-type("application/json")
  286.     %output:method("json")
  287. function interceptor:retrieve-response($state)
  288. {
  289.     if(interceptor:registration-exists($state)) then
  290.     (
  291.         if(exists(interceptor:registration-document($state)/redeemed)) then
  292.         (
  293.             interceptor:clear-secrets($state),
  294.             <rest:response>
  295.                 <http:response status="410">
  296.                     <http:header name="Access-Control-Allow-Origin" value="*"/>
  297.                 </http:response>
  298.             </rest:response>
  299.         )
  300.         else
  301.         (
  302.             if(exists(interceptor:registration-document($state)/error)) then
  303.             (
  304.                 interceptor:clear-secrets($state),
  305.                 <rest:response>
  306.                     <http:response status="403">
  307.                         <http:header name="Access-Control-Allow-Origin" value="*"/>
  308.                     </http:response>
  309.                 </rest:response>    
  310.             )
  311.             else if(not(exists(interceptor:registration-document($state)/response))) then
  312.             (
  313.                 interceptor:clear-secrets($state),
  314.                 <rest:response>
  315.                     <http:response status="404">
  316.                         <http:header name="Access-Control-Allow-Origin" value="*"/>
  317.                     </http:response>
  318.                 </rest:response>
  319.             )
  320.             else
  321.             (
  322.                 interceptor:clear-secrets($state),
  323.                 <rest:response>
  324.                     <http:response status="200">
  325.                         <http:header name="Access-Control-Allow-Origin" value="*"/>
  326.                     </http:response>
  327.                 </rest:response>,
  328.                 element root {
  329.                     for $pair in interceptor:registration-document($state)/response/json/pair
  330.                     return element r {
  331.                         attribute json:array { true() },
  332.                         element k { $pair/@name/string() },
  333.                         element v { $pair/string() }
  334.                     }
  335.                 }
  336.             ),
  337.             update insert element
  338.             redeemed {
  339.                 attribute timeStamp { util:system-dateTime() }
  340.             } into interceptor:registration-document($state),
  341.             update delete
  342.             interceptor:registration-document($state)/response/json
  343.         )
  344.     )
  345.     else
  346.     (
  347.         interceptor:clear-secrets($state),
  348.         <rest:response>
  349.             <http:response status="404">
  350.                 <http:header name="Access-Control-Allow-Origin" value="*"/>
  351.             </http:response>
  352.         </rest:response>    
  353.     )
  354. };
  355.  
  356.  
  357.  
  358. (:let $ab := update insert element dbg { element at-resp { $at } } into $registration-document:)
  359.        
  360.  
  361. (:let $body :=
  362.             <httpclient:fields>
  363.                 <httpclient:field name="code" value="{ $code }" type="string"/>
  364.                 <httpclient:field name="client_id" value="{ $registration-document/request/json/pair[@name eq "i"] }" type="string"/>
  365.                 <httpclient:field name="client_secret" value="{ $registration-document/request/json/pair[@name eq "k"] }" type="string"/>
  366.                 <httpclient:field name="redirect_uri" value="{ $registration-document/request/json/pair[@name eq "r_u"] }" type="string"/>
  367.                 {
  368.                     for $auth-field in $registration-document/request/json/pair[@name eq "t_p"]/item
  369.                     return <httpclient:field name="{ $auth-field/pair[@name eq "k"] }" value="{ $auth-field/pair[@name eq "v"] }" type="string"/>
  370.                 }
  371.             </httpclient:fields>
  372.            
  373.         let $aa := update insert element dbg { element at-fields { $body } } into $registration-document
  374.            
  375.         let $at := httpclient:post-form(
  376.             $registration-document/request/json/pair[@name eq "t_u"],
  377.             $body,
  378.             false(),
  379.             <headers><header name="Content-Type" value="application/x-www-form-urlencoded"/></headers>)
  380.         :)
Add Comment
Please, Sign In to add comment