[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/oauth2 9e3794c 01/23: New package oauth2
From: |
Stefan Monnier |
Subject: |
[elpa] externals/oauth2 9e3794c 01/23: New package oauth2 |
Date: |
Tue, 1 Dec 2020 16:31:57 -0500 (EST) |
branch: externals/oauth2
commit 9e3794cc9b24a27122191f0689886e514ea81c74
Author: Julien Danjou <julien@danjou.info>
Commit: Julien Danjou <julien@danjou.info>
New package oauth2
---
oauth2.el | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 188 insertions(+)
diff --git a/oauth2.el b/oauth2.el
new file mode 100644
index 0000000..2aea064
--- /dev/null
+++ b/oauth2.el
@@ -0,0 +1,188 @@
+;;; oauth2.el --- OAuth 2.0 Authorization Protocol
+
+;; Copyright (C) 2011 Free Software Foundation, Inc
+
+;; Author: Julien Danjou <julien@danjou.info>
+;; Version: 0.1
+;; Keywords: comm
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Implementation of the OAuth 2.0 draft.
+;;
+;; The main entry point is `oauth2-auth-and-store' which will return a token
+;; structure. This token structure can be then used with
+;; `oauth2-url-retrieve-synchronously' to retrieve any data that need OAuth
+;; authentication to be accessed.
+;;
+;; If the token needs to be refreshed, the code handles it automatically and
+;; store the new value of the access token.
+
+;;; Code:
+
+(require 'plstore)
+
+(defun oauth2-request-authorization (auth-url client-id &optional scope state)
+ "Request OAuth authorization at AUTH-URL by launching `browse-url'.
+CLIENT-ID is the client id provided by the provider.
+It returns the code provided by the service."
+ (browse-url (concat auth-url
+ (if (string-match-p "\?" auth-url) "&" "?")
+ "client_id=" client-id
+
"&response_type=code&redirect_uri=urn:ietf:wg:oauth:2.0:oob"
+ (if scope (concat "&scope=" (url-hexify-string scope))
"")
+ (if state (concat "&state=" state) "")))
+ (read-string "Enter the code your browser displayed: "))
+
+(defun oauth2-request-access-parse ()
+ "Parse the result of an OAuth request."
+ (goto-char (point-min))
+ (when (search-forward-regexp "^$" nil t)
+ (json-read)))
+
+(defun oauth2-make-access-request (url data)
+ "Make an access request to URL using DATA in POST."
+ (let ((url-request-method "POST")
+ (url-request-data data)
+ (url-request-extra-headers '(("Content-Type" .
"application/x-www-form-urlencoded"))))
+ (with-current-buffer (url-retrieve-synchronously url)
+ (let ((data (oauth2-request-access-parse)))
+ (kill-buffer (current-buffer))
+ data))))
+
+(defstruct oauth2-token
+ plstore
+ plstore-id
+ client-id
+ client-secret
+ access-token
+ refresh-token
+ token-url)
+
+(defun oauth2-request-access (token-url client-id client-secret code)
+ "Request OAuth access at TOKEN-URL.
+The CODE should be obtained with `oauth2-request-authorization'.
+Return an `oauth2-token' structure."
+ (when code
+ (let ((result
+ (oauth2-make-access-request token-url
+ (concat "client_id=" client-id
+ "&client_secret=" client-secret
+ "&code=" code
+
"&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code"))))
+ (make-oauth2-token :client-id client-id
+ :client-secret client-secret
+ :access-token (aget result 'access_token)
+ :refresh-token (aget result 'refresh_token)
+ :token-url token-url))))
+
+;;;###autoload
+(defun oauth2-refresh-access (token)
+ "Refresh OAuth access TOKEN.
+TOKEN should be obtained with `oauth2-request-access'."
+ (setf (oauth2-token-access-token token)
+ (aget (oauth2-make-access-request (oauth2-token-token-url token)
+ (concat "client_id="
(oauth2-token-client-id token)
+ "&client_secret="
(oauth2-token-client-secret token)
+ "&refresh_token="
(oauth2-token-refresh-token token)
+ "&grant_type=refresh_token"))
+ 'access_token))
+ ;; If the token has a plstore, update it
+ (let ((plstore (oauth2-token-plstore token)))
+ (when plstore
+ (plstore-put plstore (oauth2-token-plstore-id token)
+ nil `(:access-token
+ ,(oauth2-token-access-token token)
+ :refresh-token
+ ,(oauth2-token-refresh-token token)))
+ (plstore-save plstore)))
+ token)
+
+;;;###autoload
+(defun oauth2-auth (auth-url token-url client-id client-secret &optional scope
state)
+ "Authenticate application via OAuth2."
+ (oauth2-request-access
+ token-url
+ client-id
+ client-secret
+ (oauth2-request-authorization
+ auth-url client-id scope state)))
+
+(defcustom oauth2-token-file (concat user-emacs-directory "oauth2.plstore")
+ "File path where store OAuth tokens."
+ :group 'oauth2
+ :type 'file)
+
+(defun oauth2-compute-id (auth-url token-url resource-url)
+ "Compute an unique id based on URLs.
+This allows to store the token in an unique way."
+ (secure-hash 'md5 (concat auth-url token-url resource-url)))
+
+;;;###autoload
+(defun oauth2-auth-and-store (auth-url token-url resource-url client-id
client-secret)
+ "Request access to a resource and store it using `plstore'."
+ ;; We store a MD5 sum of all URL
+ (let* ((plstore (plstore-open oauth2-token-file))
+ (id (oauth2-compute-id auth-url token-url resource-url))
+ (plist (cdr (plstore-get plstore id))))
+ ;; Check if we found something matching this access
+ (if plist
+ ;; We did, return the token object
+ (make-oauth2-token :plstore plstore
+ :plstore-id id
+ :client-id client-id
+ :client-secret client-secret
+ :access-token (plist-get plist :access-token)
+ :refresh-token (plist-get plist :refresh-token)
+ :token-url token-url)
+ (let ((token (oauth2-auth auth-url token-url
+ client-id client-secret resource-url)))
+ ;; Set the plstore
+ (setf (oauth2-token-plstore token) plstore)
+ (setf (oauth2-token-plstore-id token) id)
+ (plstore-put plstore id nil `(:access-token
+ ,(oauth2-token-access-token token)
+ :refresh-token
+ ,(oauth2-token-refresh-token token)))
+ (plstore-save plstore)
+ token))))
+
+(defun oauth2-url-append-access-token (token url)
+ "Append access token to URL."
+ (concat url
+ (if (string-match-p "\?" url) "&" "?")
+ "access_token=" (oauth2-token-access-token token)))
+
+;;;###autoload
+(defun oauth2-url-retrieve-synchronously (token url)
+ "Retrieve an URL synchronously using TOKENS to access it.
+TOKENS can be obtained with `oauth2-auth'."
+ (let (tokens-need-renew)
+ (flet ((url-http-handle-authentication (proxy)
+ (setq tokens-need-renew t)
+ ;; This is to make `url' think it's
done.
+ (setq success t)))
+ (let ((url-buffer (url-retrieve-synchronously
+ (oauth2-url-append-access-token token url))))
+ (if tokens-need-renew
+ (oauth2-url-retrieve-synchronously (oauth2-refresh-access token)
url)
+ url-buffer)))))
+
+(provide 'oauth2)
+
+;;; oauth2.el ends here
- [elpa] branch externals/oauth2 created (now 7619d08), Stefan Monnier, 2020/12/01
- [elpa] externals/oauth2 9e3794c 01/23: New package oauth2,
Stefan Monnier <=
- [elpa] externals/oauth2 384ae30 03/23: * packages/oauth2/oauth2.el (oauth2-request-authorization): Add missing, Stefan Monnier, 2020/12/01
- [elpa] externals/oauth2 c1302df 06/23: oauth2: update version 0.2, Stefan Monnier, 2020/12/01
- [elpa] externals/oauth2 7513425 07/23: * packages/oauth2/oauth2.el: Fix URL double escaping, update to 0.3, Stefan Monnier, 2020/12/01
- [elpa] externals/oauth2 37cb216 12/23: oauth2: upgrade to 0.8, add missing require on cl, Stefan Monnier, 2020/12/01
- [elpa] externals/oauth2 f4f8aca 13/23: oauth2: release 0.9, require url-http, Stefan Monnier, 2020/12/01
- [elpa] externals/oauth2 e807082 02/23: * packages/oauth2/oauth2.el: Reformat to avoid long lines., Stefan Monnier, 2020/12/01
- [elpa] externals/oauth2 ba35131 05/23: oauth2: allow to use any HTTP request type, Stefan Monnier, 2020/12/01
- [elpa] externals/oauth2 e94f9f1 08/23: * packages/oauth2/oauth2.el: Don't use aget, update to 0.4, Stefan Monnier, 2020/12/01
- [elpa] externals/oauth2 a51dda4 04/23: * oauth2.el: Require json., Stefan Monnier, 2020/12/01
- [elpa] externals/oauth2 6824409 09/23: * packages/oauth2/oauth2.el: Revert fix URL double escaping, update to 0.5, Stefan Monnier, 2020/12/01