Permalink
Browse files

Merge pull request #2 from brianolson/master

fixes and improvements
  • Loading branch information...
2 parents dad73b4 + 06c2763 commit 74a9668e9352b4ed0d8f02580539f26b74353f92 @fduraffourg fduraffourg committed Sep 14, 2011
Showing with 113 additions and 122 deletions.
  1. +8 −9 authrequest.go
  2. +31 −64 verify.go
  3. +55 −46 yadis.go
  4. +19 −3 yadis_test.go
View
@@ -8,7 +8,7 @@ import (
"strings"
"io"
"os"
- "http"
+ "url"
)
const (
@@ -17,15 +17,14 @@ const (
IdentifierURL
)
-
func GetRedirectURL(Identifier string, realm string, returnto string) (string, os.Error) {
var err os.Error
var Id, IdType = NormalizeIdentifier(Identifier)
// If the identifier is an XRI, [XRI_Resolution_2.0] will yield an XRDS document that contains the necessary information. It should also be noted that Relying Parties can take advantage of XRI Proxy Resolvers, such as the one provided by XDI.org at http://www.xri.net. This will remove the need for the RPs to perform XRI Resolution locally.
if IdType == IdentifierXRI {
// Not implemented yet
- return "", os.ErrorString("XRI identifier not implemented yed")
+ return "", os.NewError("XRI identifier not implemented yed")
}
// If it is a URL, the Yadis protocol [Yadis] SHALL be first attempted. If it succeeds, the result is again an XRDS document.
@@ -36,12 +35,12 @@ func GetRedirectURL(Identifier string, realm string, returnto string) (string, o
return "", err
}
if reader == nil {
- return "", os.ErrorString("Yadis returned an empty Reader for the ID: " + Id)
+ return "", os.NewError("Yadis returned an empty Reader for the ID: " + Id)
}
var endpoint, claimedid = ParseXRDS(reader)
if len(endpoint) == 0 {
- return "", os.ErrorString("Unable to parse the XRDS document")
+ return "", os.NewError("Unable to parse the XRDS document")
}
// At this point we have the endpoint and eventually a claimed id
@@ -97,11 +96,11 @@ func CreateAuthenticationRequest(OPEndPoint, ClaimedID, Realm, ReturnTo string)
p["openid.return_to"] = Realm + ReturnTo
p["openid.realm"] = Realm
- var url string
- url = OPEndPoint + "?"
+ var url_ string
+ url_ = OPEndPoint + "?"
for k, v := range p {
- url += http.URLEscape(k) + "=" + http.URLEscape(v) + "&"
+ url_ += url.QueryEscape(k) + "=" + url.QueryEscape(v) + "&"
}
- return url
+ return url_
}
View
@@ -5,24 +5,26 @@
package openid
import (
+ "log"
"os"
"http"
"regexp"
"bytes"
+ "url"
)
// Verify that the url given match a successfull authentication
// Return:
// * true if authenticated, false otherwise
// * The Claimed identifier if authenticated
// * Eventually an error
-func Verify(url string) (grant bool, identifier string, err os.Error) {
+func Verify(url_ string) (grant bool, identifier string, err os.Error) {
grant = false
identifier = ""
err = nil
- var urlm map[string]string
- urlm, err = url2map(url)
+ var values url.Values
+ values, err = url.ParseQuery(url_)
if err != nil {
return false, "", err
}
@@ -36,38 +38,38 @@ func Verify(url string) (grant bool, identifier string, err os.Error) {
// The signature on the assertion is valid and all fields that are required to be signed are signed (Section 11.4)
- grant, err = verifyDirect(urlm)
- if err != nil {
- return
- }
-
- identifier = urlm["openid.claimed_id"]
-
- return
+ return VerifyValues(values)
}
var REVerifyDirectIsValid = "is_valid:true"
var REVerifyDirectNs = regexp.MustCompile("ns:([a-zA-Z0-9:/.]*)")
-func verifyDirect(urlm map[string]string) (grant bool, err os.Error) {
- grant = false
+// Like Verify on a parsed URL
+func VerifyValues(values url.Values) (grant bool, identifier string, err os.Error) {
err = nil
- urlm["openid.mode"] = "check_authentication"
+ var postArgs url.Values
+ postArgs = url.Values(map[string][]string{})
// Create the url
- URLEndPoint := urlm["openid.op_endpoint"]
- var postContent string
- for k, v := range urlm {
- postContent += http.URLEscape(k) + "=" + http.URLEscape(v) + "&"
+ URLEndPoint := values.Get("openid.op_endpoint")
+ if URLEndPoint == "" {
+ log.Printf("no openid.op_endpoint")
+ return false, "", os.NewError("no openid.op_endpoint")
+ }
+ for k, v := range values {
+ postArgs[k] = v
}
+ postArgs.Set("openid.mode", "check_authentication")
+ postContent := postArgs.Encode()
// Post the request
var client = new(http.Client)
postReader := bytes.NewBuffer([]byte(postContent))
response, err := client.Post(URLEndPoint, "application/x-www-form-urlencoded", postReader)
if err != nil {
- return false, err
+ log.Printf("VerifyValues failed at post")
+ return false, "", err
}
// Parse the response
@@ -76,65 +78,30 @@ func verifyDirect(urlm map[string]string) (grant bool, err os.Error) {
buffer := make([]byte, 1024)
_, err = response.Body.Read(buffer)
if err != nil {
- return false, err
+ log.Printf("VerifyValues failed reading response")
+ return false, "", err
}
// Check for ns
rematch := REVerifyDirectNs.FindSubmatch(buffer)
if rematch == nil {
- return false, os.ErrorString("verifyDirect: ns value not found on the response of the OP")
+ return false, "", os.NewError("VerifyValues: ns value not found on the response of the OP")
}
nsValue := string(rematch[1])
if !bytes.Equal([]byte(nsValue), []byte("http://specs.openid.net/auth/2.0")) {
- return false, os.ErrorString("verifyDirect: ns value not correct: " + nsValue)
+ return false, "", os.NewError("VerifyValues: ns value not correct: " + nsValue)
}
// Check for is_valid
match, err := regexp.Match(REVerifyDirectIsValid, buffer)
if err != nil {
- return false, err
+ return false, "", err
}
- return match, nil
-}
-
-// Transform an url string into a map of parameters/value
-func url2map(url string) (map[string]string, os.Error) {
- pmap := make(map[string]string)
- var start, end, eq, length int
- var param, value string
- var err os.Error
-
- length = len(url)
- start = 0
- for start < length && url[start] != '?' {
- start++
+ identifier = values.Get("openid.claimed_id")
+ if !match {
+ log.Printf("no is_valid:true in \"%s\"", buffer)
}
- if start >= length {
- start = -1
- }
- end = start
- for end < length {
- start = end + 1
- eq = start
- for eq < length && url[eq] != '=' {
- eq++
- }
- end = eq + 1
- for end < length && url[end] != '&' {
- end++
- }
-
- param, err = http.URLUnescape(url[start:eq])
- if err != nil {
- return nil, err
- }
- value, err = http.URLUnescape(url[eq+1 : end])
- if err != nil {
- return nil, err
- }
-
- pmap[param] = value
- }
- return pmap, nil
+
+ return match, identifier, nil
}
View
101 yadis.go
@@ -7,15 +7,20 @@ package openid
import (
"os"
"http"
- "xml"
- "fmt"
+ "url"
"io"
+ "io/ioutil"
"bytes"
+ "log"
+ "regexp"
"strings"
)
-
func Yadis(ID string) (io.Reader, os.Error) {
+ return YadisVerbose(ID, nil)
+}
+
+func YadisVerbose(ID string, verbose *log.Logger) (io.Reader, os.Error) {
r, err := YadisRequest(ID, "GET")
if err != nil || r == nil {
return nil, err
@@ -25,39 +30,51 @@ func Yadis(ID string) (io.Reader, os.Error) {
// If it is an XRDS document, return the Reader
if strings.HasPrefix(contentType, "application/xrds+xml") {
+ if verbose != nil {
+ verbose.Printf("got xrds from \"%s\"", ID)
+ }
return r.Body, nil
}
// If it is an HTML doc search for meta tags
if bytes.Equal([]byte(contentType), []byte("text/html")) {
- url, err := searchHTMLMetaXRDS(r.Body)
+ url_, err := searchHTMLMetaXRDS(r.Body)
if err != nil {
return nil, err
}
- return Yadis(url)
+ if verbose != nil {
+ verbose.Printf("fetching xrds found in html \"%s\"", url_)
+ }
+ return Yadis(url_)
}
// If the response contain an X-XRDS-Location header
var xrds_location = r.Header.Get("X-Xrds-Location")
if len(xrds_location) > 0 {
+ if verbose != nil {
+ verbose.Printf("fetching xrds found in http header \"%s\"", xrds_location)
+ }
return Yadis(xrds_location)
}
+ if verbose != nil {
+ verbose.Printf("Yadis fails out, nothing found. status=%#v", r.StatusCode)
+ }
// If nothing is found try to parse it as a XRDS doc
return nil, nil
}
-func YadisRequest(url string, method string) (resp *http.Response, err os.Error) {
+func YadisRequest(url_ string, method string) (resp *http.Response, err os.Error) {
resp = nil
var request = new(http.Request)
var client = new(http.Client)
var Header = make(http.Header)
request.Method = method
- request.RawURL = url
+ request.RawURL = url_
- request.URL, err = http.ParseURL(url)
+ request.URL, err = url.Parse(url_)
if err != nil {
return
}
@@ -76,56 +93,48 @@ func YadisRequest(url string, method string) (resp *http.Response, err os.Error)
for i := 0; i < 5; i++ {
response, err := client.Do(request)
+ if err != nil {
+ return nil, err
+ }
if response.StatusCode == 301 || response.StatusCode == 302 || response.StatusCode == 303 || response.StatusCode == 307 {
location := response.Header.Get("Location")
request.RawURL = location
- request.URL, err = http.ParseURL(location)
+ request.URL, err = url.Parse(location)
if err != nil {
return
}
} else {
return response, nil
}
}
- return nil, os.ErrorString("Too many redirections")
+ return nil, os.NewError("Too many redirections")
}
-func searchHTMLMetaXRDS(r io.Reader) (string, os.Error) {
- parser := xml.NewParser(r)
- var token xml.Token
- var err os.Error
- for {
- token, err = parser.Token()
- if token == nil || err != nil {
- if err == os.EOF {
- break
- }
- return "", err
- }
+var metaRE *regexp.Regexp
+var xrdsRE *regexp.Regexp
- switch token.(type) {
- case xml.StartElement:
- if token.(xml.StartElement).Name.Local == "meta" {
- // Found a meta token. Verify that it is a X-XRDS-Location and return the content
- var content string
- var contentE bool
- var httpEquivOK bool
- contentE = false
- httpEquivOK = false
- for _, v := range token.(xml.StartElement).Attr {
- if v.Name.Local == "http-equiv" && v.Value == "X-XRDS-Location" {
- httpEquivOK = true
- }
- if v.Name.Local == "content" {
- content = v.Value
- contentE = true
- }
- }
- if contentE && httpEquivOK {
- return fmt.Sprint(content), nil
- }
- }
- }
+func init() {
+ // These are ridiculous case insensitive pattern constructions.
+
+ // <[ \t]*meta[^>]*http-equiv=["']x-xrds-location["'][^>]*>
+ metaRE = regexp.MustCompile("<[ \t]*[mM][eE][tT][aA][^>]*[hH][tT][tT][pP]-[eE][qQ][uU][iI][vV]=[\"'][xX]-[xX][rR][dD][sS]-[lL][oO][cC][aA][tT][iI][oO][nN][\"'][^>]*>")
+
+ // content=["']([^"']+)["']
+ xrdsRE = regexp.MustCompile("[cC][oO][nN][tT][eE][nN][tT]=[\"']([^\"]+)[\"']")
+}
+
+func searchHTMLMetaXRDS(r io.Reader) (string, os.Error) {
+ data, err := ioutil.ReadAll(r)
+ if err != nil {
+ return "", err
+ }
+ part := metaRE.Find(data)
+ if part == nil {
+ return "", os.NewError("No -meta- match")
+ }
+ content := xrdsRE.FindSubmatch(part)
+ if content == nil {
+ return "", os.NewError("No content in meta tag: " + string(part))
}
- return "", os.ErrorString("Value not found")
+ return string(content[1]), nil
}
Oops, something went wrong.

0 comments on commit 74a9668

Please sign in to comment.