216 lines
6.7 KiB
Go
216 lines
6.7 KiB
Go
package main
|
|
|
|
// Open url in browser:
|
|
// http://localhost:14000/app
|
|
|
|
import (
|
|
"crypto/rsa"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"github.com/RangelReale/osin"
|
|
"github.com/RangelReale/osin/example"
|
|
jwt "github.com/dgrijalva/jwt-go"
|
|
)
|
|
|
|
// JWT access token generator
|
|
type AccessTokenGenJWT struct {
|
|
PrivateKey *rsa.PrivateKey
|
|
PublicKey *rsa.PublicKey
|
|
}
|
|
|
|
func (c *AccessTokenGenJWT) GenerateAccessToken(data *osin.AccessData, generaterefresh bool) (accesstoken string, refreshtoken string, err error) {
|
|
// generate JWT access token
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
|
|
"cid": data.Client.GetId(),
|
|
"exp": data.ExpireAt().Unix(),
|
|
})
|
|
|
|
accesstoken, err = token.SignedString(c.PrivateKey)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
if !generaterefresh {
|
|
return
|
|
}
|
|
|
|
// generate JWT refresh token
|
|
token = jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
|
|
"cid": data.Client.GetId(),
|
|
})
|
|
|
|
refreshtoken, err = token.SignedString(c.PrivateKey)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
return
|
|
}
|
|
|
|
func main() {
|
|
server := osin.NewServer(osin.NewServerConfig(), example.NewTestStorage())
|
|
|
|
var err error
|
|
var accessTokenGenJWT AccessTokenGenJWT
|
|
|
|
if accessTokenGenJWT.PrivateKey, err = jwt.ParseRSAPrivateKeyFromPEM(privatekeyPEM); err != nil {
|
|
fmt.Printf("ERROR: %s\n", err)
|
|
return
|
|
}
|
|
|
|
if accessTokenGenJWT.PublicKey, err = jwt.ParseRSAPublicKeyFromPEM(publickeyPEM); err != nil {
|
|
fmt.Printf("ERROR: %s\n", err)
|
|
return
|
|
}
|
|
|
|
server.AccessTokenGen = &accessTokenGenJWT
|
|
|
|
// Authorization code endpoint
|
|
http.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) {
|
|
resp := server.NewResponse()
|
|
defer resp.Close()
|
|
|
|
if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {
|
|
if !example.HandleLoginPage(ar, w, r) {
|
|
return
|
|
}
|
|
ar.Authorized = true
|
|
server.FinishAuthorizeRequest(resp, r, ar)
|
|
}
|
|
if resp.IsError && resp.InternalError != nil {
|
|
fmt.Printf("ERROR: %s\n", resp.InternalError)
|
|
}
|
|
osin.OutputJSON(resp, w, r)
|
|
})
|
|
|
|
// Access token endpoint
|
|
http.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
|
|
resp := server.NewResponse()
|
|
defer resp.Close()
|
|
|
|
if ar := server.HandleAccessRequest(resp, r); ar != nil {
|
|
ar.Authorized = true
|
|
server.FinishAccessRequest(resp, r, ar)
|
|
}
|
|
if resp.IsError && resp.InternalError != nil {
|
|
fmt.Printf("ERROR: %s\n", resp.InternalError)
|
|
}
|
|
osin.OutputJSON(resp, w, r)
|
|
})
|
|
|
|
// Information endpoint
|
|
http.HandleFunc("/info", func(w http.ResponseWriter, r *http.Request) {
|
|
resp := server.NewResponse()
|
|
defer resp.Close()
|
|
|
|
if ir := server.HandleInfoRequest(resp, r); ir != nil {
|
|
server.FinishInfoRequest(resp, r, ir)
|
|
}
|
|
osin.OutputJSON(resp, w, r)
|
|
})
|
|
|
|
// Application home endpoint
|
|
http.HandleFunc("/app", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Write([]byte("<html><body>"))
|
|
w.Write([]byte(fmt.Sprintf("<a href=\"/authorize?response_type=code&client_id=1234&state=xyz&scope=everything&redirect_uri=%s\">Login</a><br/>", url.QueryEscape("http://localhost:14000/appauth/code"))))
|
|
w.Write([]byte("</body></html>"))
|
|
})
|
|
|
|
// Application destination - CODE
|
|
http.HandleFunc("/appauth/code", func(w http.ResponseWriter, r *http.Request) {
|
|
r.ParseForm()
|
|
|
|
code := r.Form.Get("code")
|
|
|
|
w.Write([]byte("<html><body>"))
|
|
w.Write([]byte("APP AUTH - CODE<br/>"))
|
|
defer w.Write([]byte("</body></html>"))
|
|
|
|
if code == "" {
|
|
w.Write([]byte("Nothing to do"))
|
|
return
|
|
}
|
|
|
|
jr := make(map[string]interface{})
|
|
|
|
// build access code url
|
|
aurl := fmt.Sprintf("/token?grant_type=authorization_code&client_id=1234&state=xyz&redirect_uri=%s&code=%s",
|
|
url.QueryEscape("http://localhost:14000/appauth/code"), url.QueryEscape(code))
|
|
|
|
// if parse, download and parse json
|
|
if r.Form.Get("doparse") == "1" {
|
|
err := example.DownloadAccessToken(fmt.Sprintf("http://localhost:14000%s", aurl),
|
|
&osin.BasicAuth{"1234", "aabbccdd"}, jr)
|
|
if err != nil {
|
|
w.Write([]byte(err.Error()))
|
|
w.Write([]byte("<br/>"))
|
|
}
|
|
}
|
|
|
|
// show json error
|
|
if erd, ok := jr["error"]; ok {
|
|
w.Write([]byte(fmt.Sprintf("ERROR: %s<br/>\n", erd)))
|
|
}
|
|
|
|
// show json access token
|
|
if at, ok := jr["access_token"]; ok {
|
|
w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s<br/>\n", at)))
|
|
}
|
|
|
|
w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v<br/>\n", jr)))
|
|
|
|
// output links
|
|
w.Write([]byte(fmt.Sprintf("<a href=\"%s\">Goto Token URL</a><br/>", aurl)))
|
|
|
|
cururl := *r.URL
|
|
curq := cururl.Query()
|
|
curq.Add("doparse", "1")
|
|
cururl.RawQuery = curq.Encode()
|
|
w.Write([]byte(fmt.Sprintf("<a href=\"%s\">Download Token</a><br/>", cururl.String())))
|
|
})
|
|
|
|
http.ListenAndServe(":14000", nil)
|
|
}
|
|
|
|
var (
|
|
privatekeyPEM = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
|
MIIEowIBAAKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEU/wT8RDtn
|
|
SgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7mCpz9Er5qLaMXJwZxzHzAahlfA0i
|
|
cqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBpHssPnpYGIn20ZZuNlX2BrClciHhC
|
|
PUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2XrHhR+1DcKJzQBSTAGnpYVaqpsAR
|
|
ap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3bODIRe1AuTyHceAbewn8b462yEWKA
|
|
Rdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy7wIDAQABAoIBAQCwia1k7+2oZ2d3
|
|
n6agCAbqIE1QXfCmh41ZqJHbOY3oRQG3X1wpcGH4Gk+O+zDVTV2JszdcOt7E5dAy
|
|
MaomETAhRxB7hlIOnEN7WKm+dGNrKRvV0wDU5ReFMRHg31/Lnu8c+5BvGjZX+ky9
|
|
POIhFFYJqwCRlopGSUIxmVj5rSgtzk3iWOQXr+ah1bjEXvlxDOWkHN6YfpV5ThdE
|
|
KdBIPGEVqa63r9n2h+qazKrtiRqJqGnOrHzOECYbRFYhexsNFz7YT02xdfSHn7gM
|
|
IvabDDP/Qp0PjE1jdouiMaFHYnLBbgvlnZW9yuVf/rpXTUq/njxIXMmvmEyyvSDn
|
|
FcFikB8pAoGBAPF77hK4m3/rdGT7X8a/gwvZ2R121aBcdPwEaUhvj/36dx596zvY
|
|
mEOjrWfZhF083/nYWE2kVquj2wjs+otCLfifEEgXcVPTnEOPO9Zg3uNSL0nNQghj
|
|
FuD3iGLTUBCtM66oTe0jLSslHe8gLGEQqyMzHOzYxNqibxcOZIe8Qt0NAoGBAO+U
|
|
I5+XWjWEgDmvyC3TrOSf/KCGjtu0TSv30ipv27bDLMrpvPmD/5lpptTFwcxvVhCs
|
|
2b+chCjlghFSWFbBULBrfci2FtliClOVMYrlNBdUSJhf3aYSG2Doe6Bgt1n2CpNn
|
|
/iu37Y3NfemZBJA7hNl4dYe+f+uzM87cdQ214+jrAoGAXA0XxX8ll2+ToOLJsaNT
|
|
OvNB9h9Uc5qK5X5w+7G7O998BN2PC/MWp8H+2fVqpXgNENpNXttkRm1hk1dych86
|
|
EunfdPuqsX+as44oCyJGFHVBnWpm33eWQw9YqANRI+pCJzP08I5WK3osnPiwshd+
|
|
hR54yjgfYhBFNI7B95PmEQkCgYBzFSz7h1+s34Ycr8SvxsOBWxymG5zaCsUbPsL0
|
|
4aCgLScCHb9J+E86aVbbVFdglYa5Id7DPTL61ixhl7WZjujspeXZGSbmq0Kcnckb
|
|
mDgqkLECiOJW2NHP/j0McAkDLL4tysF8TLDO8gvuvzNC+WQ6drO2ThrypLVZQ+ry
|
|
eBIPmwKBgEZxhqa0gVvHQG/7Od69KWj4eJP28kq13RhKay8JOoN0vPmspXJo1HY3
|
|
CKuHRG+AP579dncdUnOMvfXOtkdM4vk0+hWASBQzM9xzVcztCa+koAugjVaLS9A+
|
|
9uQoqEeVNTckxx0S2bYevRy7hGQmUJTyQm3j1zEUR5jpdbL83Fbq
|
|
-----END RSA PRIVATE KEY-----`)
|
|
|
|
publickeyPEM = []byte(`-----BEGIN PUBLIC KEY-----
|
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41
|
|
fGnJm6gOdrj8ym3rFkEU/wT8RDtnSgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7
|
|
mCpz9Er5qLaMXJwZxzHzAahlfA0icqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBp
|
|
HssPnpYGIn20ZZuNlX2BrClciHhCPUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2
|
|
XrHhR+1DcKJzQBSTAGnpYVaqpsARap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3b
|
|
ODIRe1AuTyHceAbewn8b462yEWKARdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy
|
|
7wIDAQAB
|
|
-----END PUBLIC KEY-----`)
|
|
)
|