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  }