github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/importer/flickr/auth.go (about) 1 /* 2 Copyright 2013 The Camlistore Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package flickr 18 19 import ( 20 "fmt" 21 "net/http" 22 "net/url" 23 "strings" 24 25 "camlistore.org/pkg/httputil" 26 "camlistore.org/third_party/github.com/garyburd/go-oauth/oauth" 27 ) 28 29 var ( 30 oauthClient = &oauth.Client{ 31 TemporaryCredentialRequestURI: "http://www.flickr.com/services/oauth/request_token", 32 ResourceOwnerAuthorizationURI: "http://www.flickr.com/services/oauth/authorize", 33 TokenRequestURI: "http://www.flickr.com/services/oauth/access_token", 34 } 35 ) 36 37 type userInfo struct { 38 Id string 39 Username string 40 Cred *oauth.Credentials 41 } 42 43 func (u *userInfo) Valid() error { 44 if u.Id != "" || u.Username != "" || u.Cred.Token != "" || u.Cred.Secret != "" { 45 return fmt.Errorf("Flickr importer: Invalid user: %v", u) 46 } 47 return nil 48 } 49 50 func (im *imp) writeCredentials() error { 51 root, err := im.getRootNode() 52 if err != nil { 53 return err 54 } 55 if err := root.SetAttrs( 56 "flickrUserId", im.user.Id, 57 "flickrUsername", im.user.Username, 58 "flickrToken", im.user.Cred.Token, 59 "flickrSecret", im.user.Cred.Secret); err != nil { 60 return err 61 } 62 return nil 63 } 64 65 func (im *imp) readCredentials() error { 66 root, err := im.getRootNode() 67 if err != nil { 68 return err 69 } 70 71 u := &userInfo{ 72 Id: root.Attr("flickrUserId"), 73 Username: root.Attr("flickrUsername"), 74 Cred: &oauth.Credentials{ 75 Token: root.Attr("flickrToken"), 76 Secret: root.Attr("flickrSecret"), 77 }, 78 } 79 if err := u.Valid(); err != nil { 80 return err 81 } 82 83 im.user = u 84 return nil 85 } 86 87 func (im *imp) serveLogin(w http.ResponseWriter, r *http.Request) { 88 callback := im.host.BaseURL + "callback" 89 tempCred, err := oauthClient.RequestTemporaryCredentials(im.host.HTTPClient(), callback, nil) 90 if err != nil { 91 httputil.ServeError(w, r, fmt.Errorf("Flickr importer: Error getting temp cred: %s", err)) 92 return 93 } 94 95 // TODO(aa): If we ever have multiple frontends running this code, storing this temporary state here won't work. 96 im.user = &userInfo{Cred: tempCred} 97 98 authURL := oauthClient.AuthorizationURL(im.user.Cred, url.Values{"perms": {"read"}}) 99 http.Redirect(w, r, authURL, 302) 100 } 101 102 func (im *imp) serveCallback(w http.ResponseWriter, r *http.Request) { 103 if im.user == nil { 104 httputil.BadRequestError(w, "Flickr importer: unexpected state: expected temporary oauth session") 105 return 106 } 107 if im.user.Cred.Token != r.FormValue("oauth_token") { 108 httputil.BadRequestError(w, "Flickr importer: unexpected oauth_token") 109 return 110 } 111 tokenCred, form, err := oauthClient.RequestToken(im.host.HTTPClient(), im.user.Cred, r.FormValue("oauth_verifier")) 112 if err != nil { 113 httputil.ServeError(w, r, fmt.Errorf("Flickr importer: error getting request token: %s ", err)) 114 return 115 } 116 117 im.user = &userInfo{ 118 Id: form.Get("user_nsid"), 119 Username: form.Get("username"), 120 Cred: tokenCred, 121 } 122 im.writeCredentials() 123 http.Redirect(w, r, im.host.BaseURL+"?mode=start", 302) 124 } 125 126 func (im *imp) ServeHTTP(w http.ResponseWriter, r *http.Request) { 127 if strings.HasSuffix(r.URL.Path, "/login") { 128 im.serveLogin(w, r) 129 } else if strings.HasSuffix(r.URL.Path, "/callback") { 130 im.serveCallback(w, r) 131 } else { 132 httputil.BadRequestError(w, "Unknown path: %s", r.URL.Path) 133 } 134 }