yohcop / openid-go

OpenID consumer implementation in Go - golang
Other
83 stars 40 forks source link

How do I retrive nickname/email ? #44

Closed strk closed 7 years ago

strk commented 7 years ago

My OID provider provides nickname/email, and I know it's working because GNUSocial is able to retrive them. How do I retrive them with openid-go ?

strk commented 7 years ago

It looks like a fork does have the code to add the info: https://github.com/kushaldas/openid.go/commit/4c3f26a6e719dfe71d2eeb86143c9dc83568ac97

Would you be interested in pulling that in ? Maybe exposing a VerifyFull ?

strk commented 7 years ago

@kushaldas any reason not to send a PR yourself ?

yohcop commented 7 years ago

I took a look at the code in @kushaldas repo. I don't really like the fact that it's in Verify. I think it'd be better to keep the two things separated (handling whatever values are passed to you in the URL, which are not in the OpenID specs AFAIK, and verifying that the assertion in the URL is correct)

Your code already calls Verify with the URL, so why not just parse the info you want out of it, after calling Verify to make sure all checks out of course?

I know, the URL gets parsed twice, but I think that shouldn't be such a big deal.

strk commented 7 years ago

I haven't found that info in the parameters passed to the callback, so dunno where GNUSocial is getting them (nor the fork commit).

I surely don't like the interface change (of Verify method) but maybe adding a VerifyFull would fix that ?

yohcop commented 7 years ago

It wouldn't really help you if the info is not in the URL.

The Verify function from the above link only has the info you pass to it. If openid.sreg.email is not in the callback URL, his implementation is not going to find it.

@kushaldas's repo Verify function gets the various info from the URL:

func verify(uri string, ...) {
  parsedUrl, err := url.Parse(uri)
  // ...
  values, err := url.ParseQuery(parsedUrl.RawQuery)
  // ...
  m["email"] = values.Get("openid.sreg.email")
  // ...
  return m, nil
}

And you are calling verify directly with the uri string. So you can do the same thing in your code as well. From the example in this repo, instead of

func callbackHandler(w http.ResponseWriter, r *http.Request) {
  fullUrl := "http://localhost:8080" + r.URL.String()
  id, err := openid.Verify(fullUrl, discoveryCache, nonceStore)
  // ...
}

You would do:

func callbackHandler(w http.ResponseWriter, r *http.Request) {
  fullUrl := "http://localhost:8080" + r.URL.String()
  id, err := openid.Verify(fullUrl, discoveryCache, nonceStore)
  if err == nil {
    parsedUrl, err := url.Parse(uri)
    values, err := url.ParseQuery(parsedUrl.RawQuery)
    email := values.Get("openid.sreg.email")
    // And now you have an email
    // ...
  }
}

(plus various error handling)

I'm guessing maybe you need to request this info when you first redirect to the provider's URL?

strk commented 7 years ago

Ok, now I see. GNUSocial adds parameters to the OP call, namely:

openid.sreg.optional=nickname%2Cemail%2Cfullname%2Clanguage%2Ctimezone%2Cpostcode%2Ccountry

So I need a way to pass RedirectURL these custom parameters, right ?

xStrom commented 7 years ago

Could be. You should be able to test it by just appending it to the URL generated by RedirectURL.

yohcop commented 7 years ago

Yeah, maybe try to add it here: https://github.com/yohcop/openid-go/blob/master/redirect.go#L25

If that works, we can think about how to pass a set of url.Values to the BuildRedirectURL function!

strk commented 7 years ago

Yep, adding to the return from RedirectURL did it:

url += "&openid.sreg.optional=nickname%2Cemail"

Some support function to make encoding that easier could be useful

strk commented 7 years ago

Anyway, the question was answered, so closing this. Thanks!

strk commented 7 years ago

Now though, the openid.sreg.optional field only worked against a SimpleID provider, failing with both GNUSocial and openid.stackexchange.com :(

strk commented 7 years ago

I've filed the GNUSocial issue upstream: https://git.gnu.io/gnu/gnu-social/issues/243 But I'm not sure it's my code rather than theirs...

yohcop commented 7 years ago

The go package net/url should have everything you need to encode URL parameters.

Do they have this documented somewhere? (i.e. that adding those parameters should result in a callback with the right values?) Since both URLs end up in your browser's address bar (the redirect, and the callback), it's pretty easy to see where the problem is.

If you redirect to the right URL, the callback should have the expected values. If you don't construct the redirect URL right (escaping for example), you should also see it in your browser.

strk commented 7 years ago

Figured, I had to also pass &openid.ns.sreg=http%3A%2F%2Fopenid.net%2Fextensions%2Fsreg%2F1.1 for the stackexchange and GNUSocial support.

GNUSocial now also returns nickname/email while openid.stackexchange.com only returns email (but I think stackexchange simply doesn't have a concept of "nickname").

strk commented 7 years ago

@yohcop documentation of the extension (Simple Registration Extension) is here: https://openid.net/specs/openid-simple-registration-extension-1_0.html