git.fiddlerwoaroof.com
objects.lisp
e1ac67e4
 #|
  |Copyright (c) 2015 Edward Langley
  |All rights reserved.
  |
  |Redistribution and use in source and binary forms, with or without
  |modification, are permitted provided that the following conditions
  |are met:
  |
  |Redistributions of source code must retain the above copyright notice,
  |this list of conditions and the following disclaimer.
  |
  |Redistributions in binary form must reproduce the above copyright
  |notice, this list of conditions and the following disclaimer in the
  |documentation and/or other materials provided with the distribution.
  |
  |Neither the name of the project's author nor the names of its
  |contributors may be used to endorse or promote products derived from
  |this software without specific prior written permission.
  |
  |THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  |"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  |LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  |FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  |HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  |SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES  INCLUDING, BUT NOT LIMITED
  |TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  |PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  |LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  |NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  |SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  |
  |#
 
 (in-package :cl-oid-connect.objects)
 
 (setf drakma:*text-content-types* (cons '("application" . "json") drakma:*text-content-types*))
 
03aa798b
 (defparameter =service-info=
   (object :parents '()
           :properties '((client-id nil :accessor client-id)
                         (secret nil :accessor secret))))
e1ac67e4
 (defparameter *fbook-info* (clone =service-info=))
 (defparameter *goog-info* (clone =service-info=))
 (defparameter *endpoint-schema* nil)
 
03aa798b
 (defparameter =endpoint-schema=
   (object :parents '()
           :properties '((auth-endpoint nil :accessor auth-endpoint)
                         (token-endpoint nil :accessor token-endpoint)
                         (userinfo-endpoint nil :accessor t)
                         (auth-scope "openid profile email" :accessor t)
                         (redirect-uri nil :accessor t))))
 
e1ac67e4
 (defmessage get-user-info (a b))
 (defmessage get-access-token (a b))
 (defmessage discover-endpoints (a b c))
 
 (defreply get-user-info ((a =endpoint-schema=) (b =string=)))
 (defreply get-access-token ((a =endpoint-schema=) (b =string=)))
 
 (defreply discover-endpoints ((schema =endpoint-schema=) discovery-doc-url get-access-token)
   "Discover endpoints on the basis of a discovery document stored at a particular url.
    The two keyword arguments define a function to bind to sheeple replies for get-user-token
    and get-access-token."
   (let ((discovery-document (yason:parse (drakma:http-request discovery-doc-url))))
     (setf (auth-endpoint schema)     (gethash "authorization_endpoint" discovery-document)
           (token-endpoint schema)    (gethash "token_endpoint" discovery-document)
           (userinfo-endpoint schema) (gethash "userinfo_endpoint" discovery-document))
     (defreply get-access-token ((a schema) (b =string=))
       (funcall get-access-token a b))
 
     schema))
 
 (defparameter *goog-endpoint-schema* (defobject (=endpoint-schema= *goog-info*)))
 
 (defreply get-user-info ((endpoint-schema *goog-endpoint-schema*) (access-token =string=))
   (format t "getting user data: ~a~%" "blarg")
   (let ((endpoint (userinfo-endpoint endpoint-schema)))
     (cl-json:decode-json-from-string
       (drakma:http-request endpoint
                            :parameters `(("alt" . "json")
                                          ("access_token" . ,access-token))))))
 
 
 (defproto *fbook-endpoint-schema* (=endpoint-schema= *fbook-info*)
           ((auth-endpoint "https://www.facebook.com/dialog/oauth")
            (token-endpoint "https://graph.facebook.com/v2.3/oauth/access_token")
            (userinfo-endpoint "https://graph.facebook.com/v2.3/me")
            (auth-scope "email")
            (redirect-uri  "http://srv2.elangley.org:9090/oidc_callback/facebook")))
 
 
 (defreply get-access-token ((endpoint-schema *fbook-endpoint-schema*) (code =string=))
   (cl-json:decode-json-from-string
     (drakma:http-request (token-endpoint endpoint-schema)
                          :method :post
                          :redirect nil
                          :parameters `(("code" . ,code)
                                        ("client_id" . ,(client-id endpoint-schema))
                                        ("app_id" . ,(client-id endpoint-schema))
                                        ("client_secret" . ,(secret endpoint-schema))
                                        ("redirect_uri" . ,(redirect-uri endpoint-schema))
                                        ("grant_type" . "authorization_code")))))
 
 (defreply get-user-info ((endpoint-schema *fbook-endpoint-schema*) (access-token =string=))
   (let ((endpoint (userinfo-endpoint endpoint-schema)))
     (cl-json:decode-json-from-string
       (drakma:http-request endpoint
                            :parameters `(("access_token" . ,access-token))))))
 
 (defun do-auth-request (endpoint-schema state)
   (drakma:http-request (auth-endpoint endpoint-schema)
                        :redirect nil
                        :parameters `(("client_id" . ,(client-id endpoint-schema))
                                      ("app_id" . ,(client-id endpoint-schema))
                                      ("response_type" . "code")
                                      ("scope" . ,(auth-scope endpoint-schema))
                                      ("redirect_uri" . ,(redirect-uri endpoint-schema))
                                      ("state" . ,state))))