<commit_before>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package oauth

import (
	goauth2 "code.google.com/p/goauth2/oauth"
	"encoding/json"
	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/auth"
	"github.com/tsuru/tsuru/auth/native"
	tsuruErrors "github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/log"
	"net/http"
	"strconv"
)

var (
	ErrMissingCodeError       = &tsuruErrors.ValidationError{Message: "You must provide code to login"}
	ErrMissingCodeRedirectUrl = &tsuruErrors.ValidationError{Message: "You must provide the used redirect url to login"}
	ErrEmptyAccessToken       = &tsuruErrors.NotAuthorizedError{Message: "Couldn't convert code to access token."}
	ErrEmptyUserEmail         = &tsuruErrors.NotAuthorizedError{Message: "Couldn't parse user email."}
)

type OAuthParser interface {
	Parse(infoResponse *http.Response) (string, error)
}

type OAuthScheme struct {
	BaseConfig   goauth2.Config
	InfoUrl      string
	CallbackPort int
	Parser       OAuthParser
}

type DBTokenCache struct {
	scheme *OAuthScheme
}

func (c *DBTokenCache) Token() (*goauth2.Token, error) {
	return nil, nil
}

func (c *DBTokenCache) PutToken(t *goauth2.Token) error {
	if t.AccessToken == "" {
		return ErrEmptyAccessToken
	}
	var email string
	if t.Extra == nil || t.Extra["email"] == "" {
		conf, err := c.scheme.loadConfig()
		if err != nil {
			return err
		}
		transport := &goauth2.Transport{Config: &conf}
		transport.Token = t
		client := transport.Client()
		response, err := client.Get(c.scheme.InfoUrl)
		if err != nil {
			return err
		}
		email, err = c.scheme.Parser.Parse(response)
		if email == "" {
			return ErrEmptyUserEmail
		}
		_, err = auth.GetUserByEmail(email)
		if err != nil {
			if err != auth.ErrUserNotFound {
				return err
			}
			registrationEnabled, _ := config.GetBool("auth:user-registration")
			if !registrationEnabled {
				return err
			}
			user := auth.User{Email: email}
			err := user.Create()
			if err != nil {
				return err
			}
			err = user.CreateOnGandalf()
			if err != nil {
				return err
			}
		}
		t.Extra = make(map[string]string)
		t.Extra["email"] = email
	}
	return makeToken(t).save()
}

func init() {
	auth.RegisterScheme("oauth", &OAuthScheme{})
}

// This method loads basic config and returns a copy of the
// config object.
func (s *OAuthScheme) loadConfig() (goauth2.Config, error) {
	if s.BaseConfig.ClientId != "" {
		return s.BaseConfig, nil
	}
	if s.Parser == nil {
		s.Parser = s
	}
	var emptyConfig goauth2.Config
	clientId, err := config.GetString("auth:oauth:client-id")
	if err != nil {
		return emptyConfig, err
	}<commit_msg>auth/oauth: tries to create user on gandalf on login<commit_after>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package oauth

import (
	goauth2 "code.google.com/p/goauth2/oauth"
	"encoding/json"
	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/auth"
	"github.com/tsuru/tsuru/auth/native"
	tsuruErrors "github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/log"
	"net/http"
	"strconv"
)

var (
	ErrMissingCodeError       = &tsuruErrors.ValidationError{Message: "You must provide code to login"}
	ErrMissingCodeRedirectUrl = &tsuruErrors.ValidationError{Message: "You must provide the used redirect url to login"}
	ErrEmptyAccessToken       = &tsuruErrors.NotAuthorizedError{Message: "Couldn't convert code to access token."}
	ErrEmptyUserEmail         = &tsuruErrors.NotAuthorizedError{Message: "Couldn't parse user email."}
)

type OAuthParser interface {
	Parse(infoResponse *http.Response) (string, error)
}

type OAuthScheme struct {
	BaseConfig   goauth2.Config
	InfoUrl      string
	CallbackPort int
	Parser       OAuthParser
}

type DBTokenCache struct {
	scheme *OAuthScheme
}

func (c *DBTokenCache) Token() (*goauth2.Token, error) {
	return nil, nil
}

func (c *DBTokenCache) PutToken(t *goauth2.Token) error {
	if t.AccessToken == "" {
		return ErrEmptyAccessToken
	}
	var email string
	if t.Extra == nil || t.Extra["email"] == "" {
		conf, err := c.scheme.loadConfig()
		if err != nil {
			return err
		}
		transport := &goauth2.Transport{Config: &conf}
		transport.Token = t
		client := transport.Client()
		response, err := client.Get(c.scheme.InfoUrl)
		if err != nil {
			return err
		}
		email, err = c.scheme.Parser.Parse(response)
		if email == "" {
			return ErrEmptyUserEmail
		}
		user, err := auth.GetUserByEmail(email)
		if err != nil {
			if err != auth.ErrUserNotFound {
				return err
			}
			registrationEnabled, _ := config.GetBool("auth:user-registration")
			if !registrationEnabled {
				return err
			}
			user = &auth.User{Email: email}
			err := user.Create()
			if err != nil {
				return err
			}
		}
		err = user.CreateOnGandalf()
		if err != nil {
			log.Errorf("Ignored error trying to create user on gandalf: %s", err.Error())
		}
		t.Extra = make(map[string]string)
		t.Extra["email"] = email
	}
	return makeToken(t).save()
}

func init() {
	auth.RegisterScheme("oauth", &OAuthScheme{})
}

// This method loads basic config and returns a copy of the
// config object.
func (s *OAuthScheme) loadConfig() (goauth2.Config, error) {
	if s.BaseConfig.ClientId != "" {
		return s.BaseConfig, nil
	}
	if s.Parser == nil {
		s.Parser = s
	}
	var emptyConfig goauth2.Config
	clientId, err := config.GetString("auth:oauth:client-id")
	if err != nil {
		return emptyConfig, err
	}
{'fraction_non_alphanumeric': 0.12427953890489914, 'fraction_numerical': 0.004322766570605188, 'mean_word_length': 3.6429765886287626, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7014965', 'n_tokens_mistral': 2024, 'n_tokens_neox': 1884, 'n_words': 493}