-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implementation for web-based GitHub login (#2)
* Implementation for web-based GitHub login * Update Makefile to point to Package-Builder * Update .travis.yml
- Loading branch information
1 parent
135255e
commit 26fcfdc
Showing
10 changed files
with
313 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "Package-Builder"] | ||
path = Package-Builder | ||
url = https://github.com/IBM-Swift/Package-Builder.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
DEVELOPMENT-SNAPSHOT-2016-08-23-a |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Travis CI build file for Kitura-redis. | ||
# Kitura runs on OS X and Linux (Ubuntu v15.10). | ||
|
||
# whitelist (branches that should be built) | ||
branches: | ||
only: | ||
- master | ||
- develop | ||
- /^issue.*$/ | ||
|
||
notifications: | ||
slack: | ||
secure: "spl/MlD2mVGlto7/zMYQrswJDOM/2T/IcJ7AgrJCZ1spPZeM7HqKzgIwjlfK2Um65gzYITECTW6DEMI4pgporqHkKpCv56VCl2qoiwy3jFj2UMBFF7Bzga8hEZSygtREVz359rBZ9hfZb1+UKS/5z95Ewdm4GOIfX8GlqvWRISZqq9LpJVjw3qXg3JbRJMJJPJBCjHyEGEY4WoIYTvOifAphGNXTu9ELQeYh+Vfoq1S5lFwjwlVc7H2QYRvtQc5sNQVylq/sGbBr9AGCXUbnexmz+7VNI7+XiRcDO2EoXpHAuCZAkI+lwlXwqv2JZuHFv/1VKIRArL46pLxeQyf6RN8wWvKMfsBx/fR5KOX2InUeYeBl6yCN9A7+gMjBYamg8UuRkM7JgzChVoZz9uQrQZaQOUwo3hWbNwJK20kpAO12LKN6jOgkp+EsoRIO/j9eLxbTJBPsGIJ5YDGRUn8bMY6yg1OEiS17bmjPMIUikk8o8GXGntfHDMMTzyeYPdSmDjuaBkDs+/b5jIxERw5qVI4f3lyaFxe+S24aA6wT3sQjmBCUuo15uoSpiwsarp2k66pnNgA63oeMn+JmdInRTEgC7ZwDCMGdLZpIFt9fhHlGGvbgrhDPxmaNKe1GAWICjisQiO4GTw6iNgy4VAqGBkuG6uzNYBiLd0QfW0LlY6s=" | ||
|
||
matrix: | ||
include: | ||
- os: linux | ||
dist: trusty | ||
sudo: required | ||
- os: osx | ||
osx_image: xcode8 | ||
sudo: required | ||
|
||
before_install: | ||
- git submodule update --init --remote --merge --recursive | ||
|
||
script: | ||
- ./Package-Builder/build-package.sh $TRAVIS_BRANCH $TRAVIS_BUILD_DIR |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Contributing to Kitura | ||
|
||
We welcome contributions, but request you follow these guidelines. | ||
|
||
- [Raising issues](#raising-issues) | ||
- [Contributor License Agreement](#contributor-license-agreement) | ||
- [Coding Standards](#coding-standards) | ||
|
||
|
||
## Raising issues | ||
|
||
Please raise any bug reports on the issue tracker. Be sure to | ||
search the list to see if your issue has already been raised. | ||
|
||
A good bug report is one that make it easy for us to understand what you were | ||
trying to do and what went wrong. Provide as much context as possible so we can try to recreate the issue. | ||
|
||
### Contributor License Agreement | ||
|
||
In order for us to accept pull-requests, the contributor must first complete | ||
a Contributor License Agreement (CLA). Please see our [CLA repo](https://github.com/IBM-Swift/CLA) for more information. | ||
|
||
This clarifies the intellectual property license granted with any contribution. It is for your protection as a | ||
Contributor as well as the protection of IBM and its customers; it does not | ||
change your rights to use your own Contributions for any other purpose. | ||
|
||
### Coding standards | ||
|
||
Please ensure you follow the coding standards used throughout the existing | ||
code base. Some basic rules include: | ||
|
||
- all files must have the Apache license in the header. | ||
- all PRs must have passing builds for all operating systems. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Copyright IBM Corporation 2016 | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
# Makefile | ||
export KITURA_CI_BUILD_SCRIPTS_DIR=Package-Builder/build | ||
|
||
-include Package-Builder/build/Makefile | ||
|
||
Package-Builder/build/Makefile: | ||
@echo --- Fetching Package-Builder submodule | ||
git submodule update --init --remote --merge --recursive |
Submodule Package-Builder
added at
eff80f
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/** | ||
* Copyright IBM Corporation 2016 | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
**/ | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "Kitura-CredentialsGitHub", | ||
dependencies: [ | ||
.Package(url: "https://github.com/IBM-Swift/Kitura-Credentials.git", majorVersion: 0, minor: 28), | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# Kitura-CredentialsGitHub | ||
Plugin for the Credentials framework that authenticate using GitHub | ||
|
||
![Mac OS X](https://img.shields.io/badge/os-Mac%20OS%20X-green.svg?style=flat) | ||
![Linux](https://img.shields.io/badge/os-linux-green.svg?style=flat) | ||
![Apache 2](https://img.shields.io/badge/license-Apache2-blue.svg?style=flat) | ||
|
||
## Summary | ||
Plugin for [Kitura-Credentials](https://github.com/IBM-Swift/Kitura-Credentials) framework that authenticates using the [GitHub web login with OAuth](https://developer.github.com/v3/oauth/#web-application-flow). | ||
|
||
## Table of Contents | ||
* [Swift version](#swift-version) | ||
* [Example of GitHub web login](#example-of-github-web-login) | ||
* [License](#license) | ||
|
||
## Swift version | ||
The latest version of Kitura-CredentialsGitHub works with the DEVELOPMENT-SNAPSHOT-2016-08-23-a version of the Swift binaries. You can download this version of the Swift binaries by following this [link](https://swift.org/download/). Compatibility with other Swift versions is not guaranteed. | ||
|
||
## Example of GitHub web login | ||
First create an instance of `CredentialsGitHub` plugin and register it with `Credentials` framework: | ||
```swift | ||
import Credentials | ||
import CredentialsGitHub | ||
|
||
let credentials = Credentials() | ||
let gitCredentials = CredentialsGitHub(clientId: gitClientId, clientSecret: gitClientSecret, callbackUrl: serverUrl + "/login/github/callback", userAgent: "my-kitura-app") | ||
credentials.register(gitCredentials) | ||
``` | ||
**Where:** | ||
- *gitClientId* is the Client ID of your app in your GitHub Developer applications | ||
- *gitClientSecret* is the Client Secret of your app in your GitHub Developer applications | ||
- *userAgent* is an optional argument that passes along a User-Agent of your choice on API calls against GitHub. By default, `Kitura-CredentialsGitHub` is set as the User-Agent. [User-Agent is required when invoking GitHub APIs](https://developer.github.com/v3/#user-agent-required). | ||
|
||
**Note:** The *callbackUrl* parameter above is used to tell the GitHub web login page where the user's browser should be redirected when the login is successful. It should be a URL handled by the server you are writing. | ||
Specify where to redirect non-authenticated requests: | ||
```swift | ||
credentials.options["failureRedirect"] = "/login/github" | ||
``` | ||
|
||
Connect `credentials` middleware to requests to `/private`: | ||
|
||
```swift | ||
router.all("/private", middleware: credentials) | ||
router.get("/private/data", handler: { request, response, next in | ||
... | ||
next() | ||
}) | ||
``` | ||
And call `authenticate` to login with GitHub and to handle the redirect (callback) from the GitHub login web page after a successful login: | ||
|
||
```swift | ||
router.get("/login/github", | ||
handler: credentials.authenticate(gitCredentials.name)) | ||
|
||
router.get("/login/github/callback", | ||
handler: credentials.authenticate(gitCredentials.name)) | ||
``` | ||
## License | ||
This library is licensed under Apache 2.0. Full license text is available in [LICENSE](LICENSE.txt). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
/** | ||
* Copyright IBM Corporation 2016 | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
**/ | ||
|
||
import Kitura | ||
import KituraNet | ||
import LoggerAPI | ||
import Credentials | ||
|
||
import SwiftyJSON | ||
|
||
import Foundation | ||
|
||
public class CredentialsGitHub : CredentialsPluginProtocol { | ||
|
||
private var clientId : String | ||
|
||
private var clientSecret : String | ||
|
||
public var callbackUrl : String | ||
|
||
/// User-Agent must be set in order to access GitHub API (i.e., to get user profile) | ||
/// https://developer.github.com/v3/#user-agent-required | ||
public private(set) var userAgent: String | ||
|
||
public var name : String { | ||
return "GitHub" | ||
} | ||
|
||
public var redirecting : Bool { | ||
return true | ||
} | ||
|
||
public init (clientId: String, clientSecret : String, callbackUrl : String, userAgent: String?=nil) { | ||
self.clientId = clientId | ||
self.clientSecret = clientSecret | ||
self.callbackUrl = callbackUrl | ||
self.userAgent = userAgent ?? "Kitura-CredentialsGitHub" | ||
} | ||
|
||
public var usersCache : NSCache<NSString, BaseCacheElement>? | ||
|
||
/// https://developer.github.com/v3/oauth/#web-application-flow | ||
public func authenticate (request: RouterRequest, response: RouterResponse, | ||
options: [String:Any], onSuccess: @escaping (UserProfile) -> Void, | ||
onFailure: @escaping (HTTPStatusCode?, [String:String]?) -> Void, | ||
onPass: @escaping (HTTPStatusCode?, [String:String]?) -> Void, | ||
inProgress: @escaping () -> Void) { | ||
if let code = request.queryParameters["code"] { | ||
// query contains code: exchange code for access token | ||
var requestOptions: [ClientRequest.Options] = [] | ||
requestOptions.append(.schema("https://")) | ||
requestOptions.append(.hostname("github.com")) | ||
requestOptions.append(.method("POST")) | ||
requestOptions.append(.path("/login/oauth/access_token?client_id=\(clientId)&redirect_uri=\(callbackUrl)&client_secret=\(clientSecret)&code=\(code)")) | ||
var headers = [String:String]() | ||
headers["Accept"] = "application/json" | ||
requestOptions.append(.headers(headers)) | ||
|
||
let requestForToken = HTTP.request(requestOptions) { fbResponse in | ||
if let fbResponse = fbResponse, fbResponse.statusCode == .OK { | ||
// get user profile with access token | ||
do { | ||
var body = Data() | ||
try fbResponse.readAllData(into: &body) | ||
var jsonBody = JSON(data: body) | ||
if let token = jsonBody["access_token"].string { | ||
requestOptions = [] | ||
requestOptions.append(.schema("https://")) | ||
requestOptions.append(.hostname("api.github.com")) | ||
requestOptions.append(.method("GET")) | ||
requestOptions.append(.path("/user")) | ||
headers = [String:String]() | ||
headers["Accept"] = "application/json" | ||
headers["User-Agent"] = self.userAgent | ||
headers["Authorization"] = "token \(token)" | ||
requestOptions.append(.headers(headers)) | ||
|
||
let requestForProfile = HTTP.request(requestOptions) { profileResponse in | ||
if let profileResponse = profileResponse, profileResponse.statusCode == .OK { | ||
do { | ||
body = Data() | ||
try profileResponse.readAllData(into: &body) | ||
jsonBody = JSON(data: body) | ||
|
||
if let id = jsonBody["id"].number?.stringValue, | ||
let name = jsonBody["name"].string { | ||
let userProfile = UserProfile(id: id, displayName: name, provider: self.name) | ||
onSuccess(userProfile) | ||
return | ||
} | ||
} | ||
catch { | ||
Log.error("Failed to read \(self.name) response") | ||
} | ||
} | ||
else { | ||
onFailure(nil, nil) | ||
} | ||
} | ||
requestForProfile.end() | ||
} | ||
} | ||
catch { | ||
Log.error("Failed to read \(self.name) response") | ||
} | ||
} | ||
else { | ||
onFailure(nil, nil) | ||
} | ||
} | ||
requestForToken.end() | ||
} | ||
else { | ||
// Log in | ||
do { | ||
try response.redirect("https://github.com/login/oauth/authorize?client_id=\(clientId)&redirect_uri=\(callbackUrl)&response_type=code") | ||
inProgress() | ||
} | ||
catch { | ||
Log.error("Failed to redirect to \(name) login page") | ||
} | ||
} | ||
} | ||
} |