Coder Social home page Coder Social logo

saluto's Introduction

Saluto

Authentication (OAuth 2.0) module for RESTAS

Saluto is a submodule for RESTAS web-framework, which allow web-site users to be authorized with OAuth 2.0 protocol.

Source code: https://github.com/dmitrys99/saluto

Currently implemented OAuth 2.0 providers:

  • Facebook
  • VK.com
  • OK.ru
  • Github.com
  • Google.com
  • Mail.ru

Example usage:


(defun do-init-site ()
  (init-cache)
  (init-db)

  (restas:mount-module saluto (#:saluto)
                       (:url "auth/")
                       (:inherit-parent-context t)
                       (saluto:*providers* (list
                                            (make-instance 'saluto:oauth2-facebook.com
                                                           :name "facebook.com"
                                                           :app-id "app-id"
                                                           :app-private-key "app-key")
                                            (make-instance 'saluto:oauth2-vk.com
                                                           :name "vk.com"
                                                           :app-id "app-id"
                                                           :app-private-key "app-key")
                                            (make-instance 'saluto:oauth2-ok.ru
                                                           :name "odnoklassniki.ru"
                                                           :app-id "app-id"
                                                           :app-public-key "app-key"
                                                           :app-private-key "app-private")))
                       (saluto:*store-userinfo-fun*
                        (lambda (info)
                          (when info
                            ;; Process user info, returned by OAuth provider, like this:
                            ;; (maybe-save-user info :cache-user t :session (session-identifier))
                            ;;
                            ;; Structure of user info:
                            ;; '(:first-name "first name"
                            ;;   :last-name "last-name"
                            ;;   :email "email"
                            ;;   :uid "user id at provider level"
                            ;;   :avatar "user avatar URI"
                            ;;   :provider "provider name")
                            )))
                       (saluto:*logged-in-p-fun*
                        ;; function, called to check if user logged or not
                        (lambda ()))
                       (saluto:*logout-fun*
                        ;; function, called on logout
                        (lambda (session)
                          ;;
                          ;; (delete-userauth-from-cache session)
                          ))))

To start login process point user to URI /auth/goto/provider, ex.: http://localhost:8080/auth/goto/vk.com/

For full example usage see example.lisp.

Many thanks to https://github.com/Menschenkindlein for Lispy improvements.

saluto's People

Contributors

dmitrys99 avatar menschenkindlein avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

saluto's Issues

how do I add a new provider

I created a file azure.com.lisp

(in-package #:saluto)

(defclass oauth2-azure.com (oauth2-provider)
  ((oauth-login-url
    :initform "https://login.onmicrosoft.com/b2c_1_login/oauth2/v2.0/authorize"
    :allocation :class)
   (access-token-query-url
    :initform "https://login.onmicrosoft.com/webapivehiculos/user_impersonation"
    :allocation :class)
   (userinfo-query-url
    :initform "https://login.onmicrosoft.com/webapivehiculos/user_impersonation"
    :allocation :class)))

(defmethod make-redirect-uri ((provider oauth2-azure.com) session redirect-uri)
  (declare (ignore session redirect-uri))
  (restas:genurl* 'receiver-route
                  :provider (name provider)
                  :states ""))

(defmethod build-goto-path :around ((provider oauth2-azure.com)
                                    session
                                    redirect-uri)
  (append
   (call-next-method provider session redirect-uri)
   (list
    "response_type" "code"
    "scope" "https://mtkb2c.onmicrosoft.com/api/user_impersonation/openid/profile/offline_access"
    "state" (make-state session redirect-uri))))

(defmethod prepare-access-token-request :around ((provider
                                                  oauth2-azure.com)
                                                 code
                                                 goto-path)
  "Azure needs parameters to be send as data"
  (let ((request (call-next-method provider code goto-path)))
    (setf (getf (cdr request) :parameters)
          (concatenate-params (cons
                               '("grant_type" . "authorization_code")
                               (getf (cdr request) :parameters))))
    (substitute :content :parameters request)))

(defun remove-zeros-from-string (array)
  "This function is needed by azure.com provider,
because the answer of azure.com for unknown reasons contains sudden chunks of zeros."
  (coerce (loop for x across array unless (zerop x)
               collect (code-char x))
          'string))

(defmethod extract-access-token :around ((provider oauth2-azure.com)
                                         answer)
  (call-next-method provider (remove-zeros-from-string answer)))

(defmethod extract-userinfo :around ((provider oauth2-azure.com)
                                     answer)
  (call-next-method provider (remove-zeros-from-string answer)))

(defmethod extract-userinfo ((provider oauth2-azure.com)
                             parsed-answer)
  (labels ((code-decode (string)              ;;;; Indeed, I don't know what does it mean
             (babel:octets-to-string
              (babel:string-to-octets
               string
               :encoding :LATIN-1)
              :encoding :UTF-8)))
    (list :first-name (code-decode (json-val parsed-answer "given_name"))
          :last-name (code-decode (json-val parsed-answer "family_name"))
          :avatar (json-val parsed-answer "picture")
          :email (json-val parsed-answer "email")
          :uid (json-val parsed-answer "id"))))

and

(:defsystem saluto
  :name "Saluto"
  :author "Dmitry Solomennikov <[email protected]>"
  :version "0.0.1"
  :description "OAuth 2.0 authentication for RESTAS"
  :depends-on (#:hunchentoot
               #:restas
               #:ironclad
               #:babel
               #:split-sequence
               #:jsown
               #:cl-ppcre
               #:drakma)
  :serial t
  :components ((:file "package")
               (:file "utils")
               (:file "provider")
               (:file "routes")
               (:module "providers"
                :components ((:file "facebook.com")
                             (:file "github.com")
                             (:file "google.com")
                             (:file "mail.ru")
			     (:file "azure.com")
                             (:file "vk.com")
			     (:file "ok.ru")))))

and

(restas:define-module` #:saluto
  (:use #:cl)
  (:export #:*main*
           #:*store-userinfo-fun*
           #:*logged-in-p-fun*
           #:*logout-fun*
           #:*providers*
           #:oauth2-facebook.com
           #:oauth2-github.com
           #:oauth2-google.com
           #:oauth2-mail.ru
           #:oauth2-vk.com
	   #:oauth2-azure.com
	   #:oauth2-ok.ru))

but it gives me this error
Not Found
The requested URL /auth/goto/azure.com/ was not found on this server.
what am I doing wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.