git.fiddlerwoaroof.com
cl-oid-connect.lisp
373a5a27
 ;;;; cl-oid-connect.lisp
e09b98ca
 ;;;; TODO: Need to refactor out server names!!!
b5a8e489
 
373a5a27
 #|
b5a8e489
  |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.
  |
  |#
373a5a27
 
 (in-package :cl-oid-connect)
a43b3cd8
 ; Should this be here?
17e50f7b
 
b5a8e489
 (defun run-callback-function (endpoint-schema params get-app-user-cb get-login-data)
   (flet ((get-code (params) (assoc-cdr "code" params #'equal)))
65485bfc
     (let ((a-t (get-access-token endpoint-schema (get-code params))))
e1ac67e4
       (multiple-value-bind (access-token user-info id-token) (funcall get-login-data a-t)
         (auth-callback-skeleton params (:endpoint-schema endpoint-schema
                                         :auth-session-vars (accesstoken userinfo idtoken app-user))
65485bfc
           (setf accesstoken access-token
                 userinfo user-info
                 idtoken id-token
                 app-user (funcall get-app-user-cb user-info id-token access-token)))
         '(302 (:location "/"))))))
 
b5a8e489
 
 (defun load-provider-secrets (provider-info secrets)
   (setf (client-id provider-info) (assoc-cdr :client-id secrets)
         (secret provider-info) (assoc-cdr :secret secrets)))
3573d7f1
 
2b1f7ddf
 (defun goog-get-access-token (endpoint-schema code)
   (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))
                                        ("client_secret" . ,(secret endpoint-schema))
                                        ("redirect_uri" . ,(redirect-uri endpoint-schema))
                                        ("grant_type" . "authorization_code")))))
3573d7f1
 
2b1f7ddf
 (defun load-goog-endpoint-schema ()
   (discover-endpoints *goog-endpoint-schema*
                       "https://accounts.google.com/.well-known/openid-configuration"
e1ac67e4
                       #'goog-get-access-token)
65485bfc
   (setf (redirect-uri *goog-endpoint-schema*) "http://srv2.elangley.org:9090/oidc_callback/google"))
3573d7f1
 
e1ac67e4
 (define-auth-entry-point google-login-entry *goog-endpoint-schema*)
 (define-auth-entry-point facebook-login-entry *fbook-endpoint-schema*)
6aeb2c70
 
e1ac67e4
 (define-auth-callback google-callback *goog-endpoint-schema* (a-t)
b5a8e489
   (labels ((get-real-access-token (a-t) (assoc-cdr :access--token a-t))
            (get-id-token (a-t) (cljwt:decode (assoc-cdr :id--token a-t) :fail-if-unsupported nil)))
     (let ((access-token (get-real-access-token a-t)))
       (values access-token
         (get-user-info *goog-endpoint-schema* access-token)
         (get-id-token a-t)))))
 
e1ac67e4
 (define-auth-callback facebook-callback *fbook-endpoint-schema* (a-t)
b5a8e489
   (labels ((get-id-token (a-t) (assoc-cdr :access--token a-t)))
     ; ^-- access--token is not a mistake here
     (let ((id-token (get-id-token a-t)))
       (values a-t (get-user-info *fbook-endpoint-schema* id-token) id-token))))
 
 (defun initialize-oid-connect (facebook-info google-info)
   "Load the Google and Facebook app secrets and initialize Google's openid-configuration
    form its well-known document"
   (load-provider-secrets *fbook-info* facebook-info)
   (load-provider-secrets *goog-info* google-info) 
   (load-goog-endpoint-schema))
 
 (defun bind-oid-connect-routes (app &optional (login-callback #'identity))
   (setf (route app "/login/google" :method :get) (lambda (params) (google-login-entry params))
         (route app "/login/facebook" :method :get) (lambda (params) (facebook-login-entry params))
67a3d329
         (route app "/oidc_callback/google" :method :get) (google-callback login-callback)
b5a8e489
         (route app "/oidc_callback/facebook" :method :get) (facebook-callback login-callback)))