diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index a055df048eb2..e61da046d0aa 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -406,7 +406,7 @@ }, { "ImportPath": "github.com/RangelReale/osin", - "Rev": "1f4e9754a8931fbd9834ab11592f358418efc9ff" + "Rev": "a9958a122a90a3b069389d394284283c19d58913" }, { "ImportPath": "github.com/RangelReale/osincli", diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/access.go b/Godeps/_workspace/src/github.com/RangelReale/osin/access.go index 40075f545fc0..e6a05fd90ab2 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/access.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/access.go @@ -86,7 +86,12 @@ type AccessData struct { // IsExpired returns true if access expired func (d *AccessData) IsExpired() bool { - return d.CreatedAt.Add(time.Duration(d.ExpiresIn) * time.Second).Before(time.Now()) + return d.IsExpiredAt(time.Now()) +} + +// IsExpiredAt returns true if access expires at time 't' +func (d *AccessData) IsExpiredAt(t time.Time) bool { + return d.ExpireAt().Before(t) } // ExpireAt returns the expiration date @@ -189,7 +194,7 @@ func (s *Server) handleAuthorizationCodeRequest(w *Response, r *http.Request) *A w.SetError(E_UNAUTHORIZED_CLIENT, "") return nil } - if ret.AuthorizeData.IsExpired() { + if ret.AuthorizeData.IsExpiredAt(s.Now()) { w.SetError(E_INVALID_GRANT, "") return nil } @@ -335,7 +340,7 @@ func (s *Server) handleClientCredentialsRequest(w *Response, r *http.Request) *A ret := &AccessRequest{ Type: CLIENT_CREDENTIALS, Scope: r.Form.Get("scope"), - GenerateRefresh: true, + GenerateRefresh: false, Expiration: s.Config.AccessExpiration, HttpRequest: r, } @@ -407,7 +412,7 @@ func (s *Server) FinishAccessRequest(w *Response, r *http.Request, ar *AccessReq AuthorizeData: ar.AuthorizeData, AccessData: ar.AccessData, RedirectUri: redirectUri, - CreatedAt: time.Now(), + CreatedAt: s.Now(), ExpiresIn: ar.Expiration, UserData: ar.UserData, Scope: ar.Scope, diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/access_test.go b/Godeps/_workspace/src/github.com/RangelReale/osin/access_test.go index 1e5bb67b085b..ab6ea1eefcf8 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/access_test.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/access_test.go @@ -189,7 +189,7 @@ func TestAccessClientCredentials(t *testing.T) { t.Fatalf("Unexpected access token: %s", d) } - if d := resp.Output["refresh_token"]; d != "r1" { - t.Fatalf("Unexpected refresh token: %s", d) + if d, dok := resp.Output["refresh_token"]; dok { + t.Fatalf("Refresh token should not be generated: %s", d) } } diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/authorize.go b/Godeps/_workspace/src/github.com/RangelReale/osin/authorize.go index 1f572ebfc57d..7d9dad33dd74 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/authorize.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/authorize.go @@ -65,7 +65,12 @@ type AuthorizeData struct { // IsExpired is true if authorization expired func (d *AuthorizeData) IsExpired() bool { - return d.CreatedAt.Add(time.Duration(d.ExpiresIn) * time.Second).Before(time.Now()) + return d.IsExpiredAt(time.Now()) +} + +// IsExpired is true if authorization expires at time 't' +func (d *AuthorizeData) IsExpiredAt(t time.Time) bool { + return d.ExpireAt().Before(t) } // ExpireAt returns the expiration date @@ -221,11 +226,14 @@ func (s *Server) FinishAuthorizeRequest(w *Response, r *http.Request, ar *Author } s.FinishAccessRequest(w, r, ret) + if ar.State != "" && w.InternalError == nil { + w.Output["state"] = ar.State + } } else { // generate authorization token ret := &AuthorizeData{ Client: ar.Client, - CreatedAt: time.Now(), + CreatedAt: s.Now(), ExpiresIn: ar.Expiration, RedirectUri: ar.RedirectUri, State: ar.State, diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/example/complete/complete.go b/Godeps/_workspace/src/github.com/RangelReale/osin/example/complete/complete.go index 23cc78d10eb8..f22ce9fc1d23 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/example/complete/complete.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/example/complete/complete.go @@ -106,60 +106,59 @@ func main() { w.Write([]byte("")) w.Write([]byte("APP AUTH - CODE
")) + defer w.Write([]byte("")) - if code != "" { - 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 code == "" { + w.Write([]byte("Nothing to do")) + return + } - // 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("
")) - } - } + jr := make(map[string]interface{}) - // show json error - if erd, ok := jr["error"]; ok { - w.Write([]byte(fmt.Sprintf("ERROR: %s
\n", erd))) - } + // 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)) - // show json access token - if at, ok := jr["access_token"]; ok { - w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s
\n", at))) + // 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("
")) } + } - w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v
\n", jr))) + // show json error + if erd, ok := jr["error"]; ok { + w.Write([]byte(fmt.Sprintf("ERROR: %s
\n", erd))) + } - // output links - w.Write([]byte(fmt.Sprintf("Goto Token URL
", aurl))) + // show json access token + if at, ok := jr["access_token"]; ok { + w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s
\n", at))) + } - cururl := *r.URL - curq := cururl.Query() - curq.Add("doparse", "1") - cururl.RawQuery = curq.Encode() - w.Write([]byte(fmt.Sprintf("Download Token
", cururl.String()))) + w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v
\n", jr))) - if rt, ok := jr["refresh_token"]; ok { - rurl := fmt.Sprintf("/appauth/refresh?code=%s", rt) - w.Write([]byte(fmt.Sprintf("Refresh Token
", rurl))) - } + // output links + w.Write([]byte(fmt.Sprintf("Goto Token URL
", aurl))) - if at, ok := jr["access_token"]; ok { - rurl := fmt.Sprintf("/appauth/info?code=%s", at) - w.Write([]byte(fmt.Sprintf("Info
", rurl))) - } + cururl := *r.URL + curq := cururl.Query() + curq.Add("doparse", "1") + cururl.RawQuery = curq.Encode() + w.Write([]byte(fmt.Sprintf("Download Token
", cururl.String()))) - } else { - w.Write([]byte("Nothing to do")) + if rt, ok := jr["refresh_token"]; ok { + rurl := fmt.Sprintf("/appauth/refresh?code=%s", rt) + w.Write([]byte(fmt.Sprintf("Refresh Token
", rurl))) } - w.Write([]byte("")) + if at, ok := jr["access_token"]; ok { + rurl := fmt.Sprintf("/appauth/info?code=%s", at) + w.Write([]byte(fmt.Sprintf("Info
", rurl))) + } }) // Application destination - TOKEN @@ -187,7 +186,7 @@ func main() { aurl := fmt.Sprintf("/token?grant_type=password&scope=everything&username=%s&password=%s", "test", "test") - // doownload token + // download token err := example.DownloadAccessToken(fmt.Sprintf("http://localhost:14000%s", aurl), &osin.BasicAuth{Username: "1234", Password: "aabbccdd"}, jr) if err != nil { @@ -232,7 +231,7 @@ func main() { // build access code url aurl := fmt.Sprintf("/token?grant_type=client_credentials") - // doownload token + // download token err := example.DownloadAccessToken(fmt.Sprintf("http://localhost:14000%s", aurl), &osin.BasicAuth{Username: "1234", Password: "aabbccdd"}, jr) if err != nil { @@ -277,7 +276,7 @@ func main() { // build access code url aurl := fmt.Sprintf("/token?grant_type=assertion&assertion_type=urn:osin.example.complete&assertion=osin.data") - // doownload token + // download token err := example.DownloadAccessToken(fmt.Sprintf("http://localhost:14000%s", aurl), &osin.BasicAuth{Username: "1234", Password: "aabbccdd"}, jr) if err != nil { @@ -316,49 +315,49 @@ func main() { w.Write([]byte("")) w.Write([]byte("APP AUTH - REFRESH
")) + defer w.Write([]byte("")) code := r.Form.Get("code") - if code != "" { - jr := make(map[string]interface{}) + if code == "" { + w.Write([]byte("Nothing to do")) + return + } - // build access code url - aurl := fmt.Sprintf("/token?grant_type=refresh_token&refresh_token=%s", url.QueryEscape(code)) + jr := make(map[string]interface{}) - // doownload token - err := example.DownloadAccessToken(fmt.Sprintf("http://localhost:14000%s", aurl), - &osin.BasicAuth{Username: "1234", Password: "aabbccdd"}, jr) - if err != nil { - w.Write([]byte(err.Error())) - w.Write([]byte("
")) - } + // build access code url + aurl := fmt.Sprintf("/token?grant_type=refresh_token&refresh_token=%s", url.QueryEscape(code)) - // show json error - if erd, ok := jr["error"]; ok { - w.Write([]byte(fmt.Sprintf("ERROR: %s
\n", erd))) - } + // download token + err := example.DownloadAccessToken(fmt.Sprintf("http://localhost:14000%s", aurl), + &osin.BasicAuth{Username: "1234", Password: "aabbccdd"}, jr) + if err != nil { + w.Write([]byte(err.Error())) + w.Write([]byte("
")) + } - // show json access token - if at, ok := jr["access_token"]; ok { - w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s
\n", at))) - } + // show json error + if erd, ok := jr["error"]; ok { + w.Write([]byte(fmt.Sprintf("ERROR: %s
\n", erd))) + } - w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v
\n", jr))) + // show json access token + if at, ok := jr["access_token"]; ok { + w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s
\n", at))) + } - if rt, ok := jr["refresh_token"]; ok { - rurl := fmt.Sprintf("/appauth/refresh?code=%s", rt) - w.Write([]byte(fmt.Sprintf("Refresh Token
", rurl))) - } + w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v
\n", jr))) - if at, ok := jr["access_token"]; ok { - rurl := fmt.Sprintf("/appauth/info?code=%s", at) - w.Write([]byte(fmt.Sprintf("Info
", rurl))) - } - } else { - w.Write([]byte("Nothing to do")) + if rt, ok := jr["refresh_token"]; ok { + rurl := fmt.Sprintf("/appauth/refresh?code=%s", rt) + w.Write([]byte(fmt.Sprintf("Refresh Token
", rurl))) } - w.Write([]byte("")) + if at, ok := jr["access_token"]; ok { + rurl := fmt.Sprintf("/appauth/info?code=%s", at) + w.Write([]byte(fmt.Sprintf("Info
", rurl))) + } }) // Application destination - INFO @@ -367,44 +366,44 @@ func main() { w.Write([]byte("")) w.Write([]byte("APP AUTH - INFO
")) + defer w.Write([]byte("")) code := r.Form.Get("code") - if code != "" { - jr := make(map[string]interface{}) - - // build access code url - aurl := fmt.Sprintf("/info?code=%s", url.QueryEscape(code)) + if code == "" { + w.Write([]byte("Nothing to do")) + return + } - // doownload token - err := example.DownloadAccessToken(fmt.Sprintf("http://localhost:14000%s", aurl), - &osin.BasicAuth{Username: "1234", Password: "aabbccdd"}, jr) - if err != nil { - w.Write([]byte(err.Error())) - w.Write([]byte("
")) - } + jr := make(map[string]interface{}) - // show json error - if erd, ok := jr["error"]; ok { - w.Write([]byte(fmt.Sprintf("ERROR: %s
\n", erd))) - } + // build access code url + aurl := fmt.Sprintf("/info?code=%s", url.QueryEscape(code)) - // show json access token - if at, ok := jr["access_token"]; ok { - w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s
\n", at))) - } + // download token + err := example.DownloadAccessToken(fmt.Sprintf("http://localhost:14000%s", aurl), + &osin.BasicAuth{Username: "1234", Password: "aabbccdd"}, jr) + if err != nil { + w.Write([]byte(err.Error())) + w.Write([]byte("
")) + } - w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v
\n", jr))) + // show json error + if erd, ok := jr["error"]; ok { + w.Write([]byte(fmt.Sprintf("ERROR: %s
\n", erd))) + } - if rt, ok := jr["refresh_token"]; ok { - rurl := fmt.Sprintf("/appauth/refresh?code=%s", rt) - w.Write([]byte(fmt.Sprintf("Refresh Token
", rurl))) - } - } else { - w.Write([]byte("Nothing to do")) + // show json access token + if at, ok := jr["access_token"]; ok { + w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s
\n", at))) } - w.Write([]byte("")) + w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v
\n", jr))) + + if rt, ok := jr["refresh_token"]; ok { + rurl := fmt.Sprintf("/appauth/refresh?code=%s", rt) + w.Write([]byte(fmt.Sprintf("Refresh Token
", rurl))) + } }) http.ListenAndServe(":14000", nil) diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/example/goauth2client/goauth2client.go b/Godeps/_workspace/src/github.com/RangelReale/osin/example/goauth2client/goauth2client.go index 714abe154587..b35bfb51e710 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/example/goauth2client/goauth2client.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/example/goauth2client/goauth2client.go @@ -88,41 +88,40 @@ func main() { w.Write([]byte("")) w.Write([]byte("APP AUTH - CODE
")) + defer w.Write([]byte("")) - if code != "" { + if code == "" { + w.Write([]byte("Nothing to do")) + return + } - var jr *oauth.Token - var err error + var jr *oauth.Token + var err error - // if parse, download and parse json - if r.Form.Get("doparse") == "1" { - jr, err = ctransport.Exchange(code) - if err != nil { - jr = nil - w.Write([]byte(fmt.Sprintf("ERROR: %s
\n", err))) - } + // if parse, download and parse json + if r.Form.Get("doparse") == "1" { + jr, err = ctransport.Exchange(code) + if err != nil { + jr = nil + w.Write([]byte(fmt.Sprintf("ERROR: %s
\n", err))) } + } - // show json access token - if jr != nil { - w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s
\n", jr.AccessToken))) - if jr.RefreshToken != "" { - w.Write([]byte(fmt.Sprintf("REFRESH TOKEN: %s
\n", jr.RefreshToken))) - } + // show json access token + if jr != nil { + w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s
\n", jr.AccessToken))) + if jr.RefreshToken != "" { + w.Write([]byte(fmt.Sprintf("REFRESH TOKEN: %s
\n", jr.RefreshToken))) } - - w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v
\n", jr))) - - cururl := *r.URL - curq := cururl.Query() - curq.Add("doparse", "1") - cururl.RawQuery = curq.Encode() - w.Write([]byte(fmt.Sprintf("Download Token
", cururl.String()))) - } else { - w.Write([]byte("Nothing to do")) } - w.Write([]byte("")) + w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v
\n", jr))) + + cururl := *r.URL + curq := cururl.Query() + curq.Add("doparse", "1") + cururl.RawQuery = curq.Encode() + w.Write([]byte(fmt.Sprintf("Download Token
", cururl.String()))) }) http.ListenAndServe(":14000", nil) diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/example/jwttoken/jwttoken.go b/Godeps/_workspace/src/github.com/RangelReale/osin/example/jwttoken/jwttoken.go index 20719d6bf959..25269478cde0 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/example/jwttoken/jwttoken.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/example/jwttoken/jwttoken.go @@ -29,18 +29,19 @@ func (c *AccessTokenGenJWT) GenerateAccessToken(data *osin.AccessData, generater return "", "", err } - if generaterefresh { + if !generaterefresh { + return + } - // generate JWT access token - token = jwt.New(jwt.GetSigningMethod("RS256")) - token.Claims["cid"] = data.Client.GetId() - token.Claims["at"] = accesstoken - token.Claims["exp"] = data.ExpireAt().Unix() + // generate JWT access token + token = jwt.New(jwt.GetSigningMethod("RS256")) + token.Claims["cid"] = data.Client.GetId() + token.Claims["at"] = accesstoken + token.Claims["exp"] = data.ExpireAt().Unix() - refreshtoken, err = token.SignedString(c.PrivateKey) - if err != nil { - return "", "", err - } + refreshtoken, err = token.SignedString(c.PrivateKey) + if err != nil { + return "", "", err } return } @@ -108,49 +109,49 @@ func main() { w.Write([]byte("")) w.Write([]byte("APP AUTH - CODE
")) + defer w.Write([]byte("")) - if code != "" { - 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("
")) - } - } + if code == "" { + w.Write([]byte("Nothing to do")) + return + } - // show json error - if erd, ok := jr["error"]; ok { - w.Write([]byte(fmt.Sprintf("ERROR: %s
\n", erd))) - } + jr := make(map[string]interface{}) - // show json access token - if at, ok := jr["access_token"]; ok { - w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s
\n", at))) - } + // 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)) - w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v
\n", jr))) + // 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("
")) + } + } - // output links - w.Write([]byte(fmt.Sprintf("Goto Token URL
", aurl))) + // show json error + if erd, ok := jr["error"]; ok { + w.Write([]byte(fmt.Sprintf("ERROR: %s
\n", erd))) + } - cururl := *r.URL - curq := cururl.Query() - curq.Add("doparse", "1") - cururl.RawQuery = curq.Encode() - w.Write([]byte(fmt.Sprintf("Download Token
", cururl.String()))) - } else { - w.Write([]byte("Nothing to do")) + // show json access token + if at, ok := jr["access_token"]; ok { + w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s
\n", at))) } - w.Write([]byte("")) + w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v
\n", jr))) + + // output links + w.Write([]byte(fmt.Sprintf("Goto Token URL
", aurl))) + + cururl := *r.URL + curq := cururl.Query() + curq.Add("doparse", "1") + cururl.RawQuery = curq.Encode() + w.Write([]byte(fmt.Sprintf("Download Token
", cururl.String()))) }) http.ListenAndServe(":14000", nil) diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/example/osincliclient/osincliclient.go b/Godeps/_workspace/src/github.com/RangelReale/osin/example/osincliclient/osincliclient.go index 969fea58fbcf..98916fe30944 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/example/osincliclient/osincliclient.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/example/osincliclient/osincliclient.go @@ -101,23 +101,25 @@ func main() { // Auth endpoint clienthttp.HandleFunc("/appauth", func(w http.ResponseWriter, r *http.Request) { // parse a token request - if areqdata, err := areq.HandleRequest(r); err == nil { - treq := client.NewAccessRequest(osincli.AUTHORIZATION_CODE, areqdata) - - // show access request url (for debugging only) - u2 := treq.GetTokenUrl() - w.Write([]byte(fmt.Sprintf("Access token URL: %s\n", u2.String()))) - - // exchange the authorize token for the access token - ad, err := treq.GetToken() - if err == nil { - w.Write([]byte(fmt.Sprintf("Access token: %+v\n", ad))) - } else { - w.Write([]byte(fmt.Sprintf("ERROR: %s\n", err))) - } - } else { + areqdata, err := areq.HandleRequest(r) + if err != nil { + w.Write([]byte(fmt.Sprintf("ERROR: %s\n", err))) + return + } + + treq := client.NewAccessRequest(osincli.AUTHORIZATION_CODE, areqdata) + + // show access request url (for debugging only) + u2 := treq.GetTokenUrl() + w.Write([]byte(fmt.Sprintf("Access token URL: %s\n", u2.String()))) + + // exchange the authorize token for the access token + ad, err := treq.GetToken() + if err != nil { w.Write([]byte(fmt.Sprintf("ERROR: %s\n", err))) + return } + w.Write([]byte(fmt.Sprintf("Access token: %+v\n", ad))) }) go http.ListenAndServe(":14001", clienthttp) diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/example/simple/simple.go b/Godeps/_workspace/src/github.com/RangelReale/osin/example/simple/simple.go index 4dbd6c7c220a..6b14843e63c0 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/example/simple/simple.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/example/simple/simple.go @@ -77,49 +77,49 @@ func main() { w.Write([]byte("")) w.Write([]byte("APP AUTH - CODE
")) + defer w.Write([]byte("")) - if code != "" { - jr := make(map[string]interface{}) - - // build access code url - aurl := fmt.Sprintf("/token?grant_type=authorization_code&client_id=1234&client_secret=aabbccdd&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("
")) - } - } + if code == "" { + w.Write([]byte("Nothing to do")) + return + } - // show json error - if erd, ok := jr["error"]; ok { - w.Write([]byte(fmt.Sprintf("ERROR: %s
\n", erd))) - } + jr := make(map[string]interface{}) - // show json access token - if at, ok := jr["access_token"]; ok { - w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s
\n", at))) - } + // build access code url + aurl := fmt.Sprintf("/token?grant_type=authorization_code&client_id=1234&client_secret=aabbccdd&state=xyz&redirect_uri=%s&code=%s", + url.QueryEscape("http://localhost:14000/appauth/code"), url.QueryEscape(code)) - w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v
\n", jr))) + // 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("
")) + } + } - // output links - w.Write([]byte(fmt.Sprintf("Goto Token URL
", aurl))) + // show json error + if erd, ok := jr["error"]; ok { + w.Write([]byte(fmt.Sprintf("ERROR: %s
\n", erd))) + } - cururl := *r.URL - curq := cururl.Query() - curq.Add("doparse", "1") - cururl.RawQuery = curq.Encode() - w.Write([]byte(fmt.Sprintf("Download Token
", cururl.String()))) - } else { - w.Write([]byte("Nothing to do")) + // show json access token + if at, ok := jr["access_token"]; ok { + w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s
\n", at))) } - w.Write([]byte("")) + w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v
\n", jr))) + + // output links + w.Write([]byte(fmt.Sprintf("Goto Token URL
", aurl))) + + cururl := *r.URL + curq := cururl.Query() + curq.Add("doparse", "1") + cururl.RawQuery = curq.Encode() + w.Write([]byte(fmt.Sprintf("Download Token
", cururl.String()))) }) http.ListenAndServe(":14000", nil) diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/info.go b/Godeps/_workspace/src/github.com/RangelReale/osin/info.go index 99412b0c5950..00aa563c619f 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/info.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/info.go @@ -15,10 +15,15 @@ type InfoRequest struct { // NOT an RFC specification. func (s *Server) HandleInfoRequest(w *Response, r *http.Request) *InfoRequest { r.ParseForm() + bearer := CheckBearerAuth(r) + if bearer == nil { + w.SetError(E_INVALID_REQUEST, "") + return nil + } // generate info request ret := &InfoRequest{ - Code: r.Form.Get("code"), + Code: bearer.Code, } if ret.Code == "" { @@ -47,7 +52,7 @@ func (s *Server) HandleInfoRequest(w *Response, r *http.Request) *InfoRequest { w.SetError(E_UNAUTHORIZED_CLIENT, "") return nil } - if ret.AccessData.IsExpired() { + if ret.AccessData.IsExpiredAt(s.Now()) { w.SetError(E_INVALID_GRANT, "") return nil } @@ -66,7 +71,7 @@ func (s *Server) FinishInfoRequest(w *Response, r *http.Request, ir *InfoRequest w.Output["client_id"] = ir.AccessData.Client.GetId() w.Output["access_token"] = ir.AccessData.AccessToken w.Output["token_type"] = s.Config.TokenType - w.Output["expires_in"] = ir.AccessData.CreatedAt.Add(time.Duration(ir.AccessData.ExpiresIn)*time.Second).Sub(time.Now()) / time.Second + w.Output["expires_in"] = ir.AccessData.CreatedAt.Add(time.Duration(ir.AccessData.ExpiresIn)*time.Second).Sub(s.Now()) / time.Second if ir.AccessData.RefreshToken != "" { w.Output["refresh_token"] = ir.AccessData.RefreshToken } diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/info_test.go b/Godeps/_workspace/src/github.com/RangelReale/osin/info_test.go index cdc111df1844..c0737080b863 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/info_test.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/info_test.go @@ -22,7 +22,37 @@ func TestInfo(t *testing.T) { server.FinishInfoRequest(resp, req, ar) } - //fmt.Printf("%+v", resp) + if resp.IsError && resp.InternalError != nil { + t.Fatalf("Error in response: %s", resp.InternalError) + } + + if resp.IsError { + t.Fatalf("Should not be an error") + } + + if resp.Type != DATA { + t.Fatalf("Response should be data") + } + + if d := resp.Output["access_token"]; d != "9999" { + t.Fatalf("Unexpected authorization code: %s", d) + } +} + +func TestInfoWhenCodeIsOnHeader(t *testing.T) { + sconfig := NewServerConfig() + server := NewServer(sconfig, NewTestingStorage()) + resp := server.NewResponse() + + req, err := http.NewRequest("GET", "http://localhost:14000/appauth", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer 9999") + + if ar := server.HandleInfoRequest(resp, req); ar != nil { + server.FinishInfoRequest(resp, req, ar) + } if resp.IsError && resp.InternalError != nil { t.Fatalf("Error in response: %s", resp.InternalError) diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/response.go b/Godeps/_workspace/src/github.com/RangelReale/osin/response.go index 4532047ff7a8..ce6174978e09 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/response.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/response.go @@ -45,7 +45,12 @@ func NewResponse(storage Storage) *Response { IsError: false, Storage: storage.Clone(), } - r.Headers.Add("Cache-Control", "no-store") + r.Headers.Add( + "Cache-Control", + "no-cache, no-store, max-age=0, must-revalidate", + ) + r.Headers.Add("Pragma", "no-cache") + r.Headers.Add("Expires", "Fri, 01 Jan 1990 00:00:00 GMT") return r } @@ -117,7 +122,10 @@ func (r *Response) GetRedirectUrl() (string, error) { } if r.RedirectInFragment { u.RawQuery = "" - u.Fragment = q.Encode() + u.Fragment, err = url.QueryUnescape(q.Encode()) + if err != nil { + return "", err + } } else { u.RawQuery = q.Encode() } diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/server.go b/Godeps/_workspace/src/github.com/RangelReale/osin/server.go index 4ebac260deee..57695aee6a74 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/server.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/server.go @@ -1,7 +1,7 @@ package osin import ( - "net/http" + "time" ) // Server is an OAuth2 implementation @@ -10,6 +10,7 @@ type Server struct { Storage Storage AuthorizeTokenGen AuthorizeTokenGen AccessTokenGen AccessTokenGen + Now func() time.Time } // NewServer creates a new server instance @@ -19,21 +20,13 @@ func NewServer(config *ServerConfig, storage Storage) *Server { Storage: storage, AuthorizeTokenGen: &AuthorizeTokenGenDefault{}, AccessTokenGen: &AccessTokenGenDefault{}, + Now: time.Now, } } // NewResponse creates a new response for the server func (s *Server) NewResponse() *Response { - r := &Response{ - Type: DATA, - StatusCode: 200, - ErrorStatusCode: 200, - Output: make(ResponseData), - Headers: make(http.Header), - IsError: false, - Storage: s.Storage.Clone(), - } - r.Headers.Add("Cache-Control", "no-store") + r := NewResponse(s.Storage) r.ErrorStatusCode = s.Config.ErrorStatusCode return r } diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/storage.go b/Godeps/_workspace/src/github.com/RangelReale/osin/storage.go index 77334b602eb7..d3dea967cc8c 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/storage.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/storage.go @@ -10,7 +10,7 @@ type Storage interface { // Can return itself if not a problem. Clone() Storage - // Close the resources the Storate potentially holds (using Clone for example) + // Close the resources the Storage potentially holds (using Clone for example) Close() // GetClient loads the client by id (client_id) diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/tokengen.go b/Godeps/_workspace/src/github.com/RangelReale/osin/tokengen.go index 89b61761d0e2..73de7ca72853 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/tokengen.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/tokengen.go @@ -1,18 +1,24 @@ package osin import ( - "code.google.com/p/go-uuid/uuid" "encoding/base64" + "strings" + + "code.google.com/p/go-uuid/uuid" ) // AuthorizeTokenGenDefault is the default authorization token generator type AuthorizeTokenGenDefault struct { } +func removePadding(token string) string { + return strings.TrimRight(token, "=") +} + // GenerateAuthorizeToken generates a base64-encoded UUID code func (a *AuthorizeTokenGenDefault) GenerateAuthorizeToken(data *AuthorizeData) (ret string, err error) { - token := uuid.New() - return base64.StdEncoding.EncodeToString([]byte(token)), nil + token := uuid.NewRandom() + return removePadding(base64.URLEncoding.EncodeToString([]byte(token))), nil } // AccessTokenGenDefault is the default authorization token generator @@ -21,12 +27,12 @@ type AccessTokenGenDefault struct { // GenerateAccessToken generates base64-encoded UUID access and refresh tokens func (a *AccessTokenGenDefault) GenerateAccessToken(data *AccessData, generaterefresh bool) (accesstoken string, refreshtoken string, err error) { - accesstoken = uuid.New() - accesstoken = base64.StdEncoding.EncodeToString([]byte(accesstoken)) + token := uuid.NewRandom() + accesstoken = removePadding(base64.URLEncoding.EncodeToString([]byte(token))) if generaterefresh { - refreshtoken = uuid.New() - refreshtoken = base64.StdEncoding.EncodeToString([]byte(refreshtoken)) + rtoken := uuid.NewRandom() + refreshtoken = removePadding(base64.URLEncoding.EncodeToString([]byte(rtoken))) } return } diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/util.go b/Godeps/_workspace/src/github.com/RangelReale/osin/util.go index 4d416d029e5b..c10f53552297 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/util.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/util.go @@ -13,6 +13,11 @@ type BasicAuth struct { Password string } +// Parse bearer authentication header +type BearerAuth struct { + Code string +} + // Return authorization header data func CheckBasicAuth(r *http.Request) (*BasicAuth, error) { if r.Header.Get("Authorization") == "" { @@ -36,6 +41,24 @@ func CheckBasicAuth(r *http.Request) (*BasicAuth, error) { return &BasicAuth{Username: pair[0], Password: pair[1]}, nil } +// Return "Bearer" token from request. The header has precedence over query string. +func CheckBearerAuth(r *http.Request) *BearerAuth { + authHeader := r.Header.Get("Authorization") + authForm := r.Form.Get("code") + if authHeader == "" && authForm == "" { + return nil + } + token := authForm + if authHeader != "" { + s := strings.SplitN(authHeader, " ", 2) + if (len(s) != 2 || s[0] != "Bearer") && token == "" { + return nil + } + token = s[1] + } + return &BearerAuth{Code: token} +} + // getClientAuth checks client basic authentication in params if allowed, // otherwise gets it from the header. // Sets an error on the response if no auth is present or a server error occurs. diff --git a/Godeps/_workspace/src/github.com/RangelReale/osin/util_test.go b/Godeps/_workspace/src/github.com/RangelReale/osin/util_test.go index efec29313285..34ddf6c0a726 100644 --- a/Godeps/_workspace/src/github.com/RangelReale/osin/util_test.go +++ b/Godeps/_workspace/src/github.com/RangelReale/osin/util_test.go @@ -7,8 +7,9 @@ import ( ) const ( - badAuthValue = "Digest XHHHHHHH" - goodAuthValue = "Basic dGVzdDp0ZXN0" + badAuthValue = "Digest XHHHHHHH" + goodAuthValue = "Basic dGVzdDp0ZXN0" + goodBearerAuthValue = "Bearer BGFVTDUJDp0ZXN0" ) func TestBasicAuth(t *testing.T) { @@ -94,3 +95,42 @@ func TestGetClientAuth(t *testing.T) { } } + +func TestBearerAuth(t *testing.T) { + r := &http.Request{Header: make(http.Header)} + + // Without any header + if b := CheckBearerAuth(r); b != nil { + t.Errorf("Validated bearer auth without header") + } + + // with invalid header + r.Header.Set("Authorization", badAuthValue) + b := CheckBearerAuth(r) + if b != nil { + t.Errorf("Validated invalid auth") + return + } + + // with valid header + r.Header.Set("Authorization", goodBearerAuthValue) + b = CheckBearerAuth(r) + if b == nil { + t.Errorf("Could not extract bearer auth") + return + } + + // check extracted auth data + if b.Code != "BGFVTDUJDp0ZXN0" { + t.Errorf("Error decoding bearer auth") + } + + // extracts bearer auth from query string + url, _ := url.Parse("http://host.tld/path?code=XYZ") + r = &http.Request{URL: url} + r.ParseForm() + b = CheckBearerAuth(r) + if b.Code != "XYZ" { + t.Errorf("Error decoding bearer auth") + } +} diff --git a/pkg/oauth/server/osinserver/osinserver.go b/pkg/oauth/server/osinserver/osinserver.go index d0df9ed755b7..d305f10f0047 100644 --- a/pkg/oauth/server/osinserver/osinserver.go +++ b/pkg/oauth/server/osinserver/osinserver.go @@ -23,9 +23,15 @@ type Server struct { } func New(config *osin.ServerConfig, storage osin.Storage, authorize AuthorizeHandler, access AccessHandler, errorHandler ErrorHandler) *Server { + server := osin.NewServer(config, storage) + + // Override tokengen to ensure we get valid length tokens + server.AuthorizeTokenGen = &AuthorizeTokenGen{} + server.AccessTokenGen = &AccessTokenGen{} + return &Server{ config: config, - server: osin.NewServer(config, storage), + server: server, authorize: authorize, access: access, errorHandler: errorHandler, diff --git a/pkg/oauth/server/osinserver/tokengen.go b/pkg/oauth/server/osinserver/tokengen.go new file mode 100644 index 000000000000..cf252a840ecf --- /dev/null +++ b/pkg/oauth/server/osinserver/tokengen.go @@ -0,0 +1,45 @@ +package osinserver + +import ( + "encoding/base64" + "strings" + + "code.google.com/p/go-uuid/uuid" + + "github.com/RangelReale/osin" +) + +func randomToken() string { + // Two random uuids to get the length we want (> 32 chars when base-64 encoded) + b := []byte{} + b = append(b, []byte(uuid.NewRandom())...) + b = append(b, []byte(uuid.NewRandom())...) + // Use URLEncoding to ensure we don't get / characters + s := base64.URLEncoding.EncodeToString(b) + // Strip trailing ='s... they're ugly + return strings.TrimRight(s, "=") +} + +// AuthorizeTokenGen is an authorization token generator +type AuthorizeTokenGen struct { +} + +// GenerateAuthorizeToken generates a random UUID code +func (a *AuthorizeTokenGen) GenerateAuthorizeToken(data *osin.AuthorizeData) (ret string, err error) { + return randomToken(), nil +} + +// AccessTokenGen is an access token generator +type AccessTokenGen struct { +} + +// GenerateAccessToken generates random UUID access and refresh tokens +func (a *AccessTokenGen) GenerateAccessToken(data *osin.AccessData, generaterefresh bool) (string, string, error) { + accesstoken := randomToken() + + refreshtoken := "" + if generaterefresh { + refreshtoken = randomToken() + } + return accesstoken, refreshtoken, nil +}