auth

Paddy 2015-01-04 Parent:c03b5eb3179e Child:9a5999963868

108:2e4b5722eed0 Browse Files

Add support for registering Clients. Add an API endpoint to register Clients, which was the last step necessary before the OAuth2 integration could be tried out.

authd/server.go authd/templates/simple.gotmpl client.go request.go

     1.1 --- a/authd/server.go	Wed Dec 17 22:27:44 2014 -0500
     1.2 +++ b/authd/server.go	Sun Jan 04 00:07:27 2015 -0500
     1.3 @@ -33,6 +33,7 @@
     1.4  	auth.RegisterOAuth2(router, context)
     1.5  	auth.RegisterSessionHandlers(router, context)
     1.6  	auth.RegisterProfileHandlers(router, context)
     1.7 +	auth.RegisterClientHandlers(router, context)
     1.8  	http.Handle("/", router)
     1.9  	log.Fatal(http.ListenAndServe(":8080", nil))
    1.10  }
     2.1 --- a/authd/templates/simple.gotmpl	Wed Dec 17 22:27:44 2014 -0500
     2.2 +++ b/authd/templates/simple.gotmpl	Sun Jan 04 00:07:27 2015 -0500
     2.3 @@ -25,6 +25,9 @@
     2.4  		<p>{{ .error }}</p>{{ end }}{{ if .internal_error }}
     2.5  		<h1>Error</h1>
     2.6  		<p>{{ .internal_error }}</p>{{ end }}{{ if not .error }}{{ if not .internal_error }}<h1>Grant access</h1>
     2.7 -		<p>{{ .client }} is requesting access to your account. if you grant it, you'll be redirected to {{ .redirectURL }}. Their access will be limited to {{ .scope }}. You are granting access for {{ .profile }}.</p>{{ end }}{{ end }}
     2.8 +		<p>{{ .client.Name }} is requesting access to your account. if you grant it, you'll be redirected to {{ .redirectURL }}. Their access will be limited to {{ .scope }}. You are granting access for {{ .profile.Name }}.</p>{{ end }}{{ end }}
     2.9 +		<form method="POST">
    2.10 +			<input type="submit" name="grant" value="approved">
    2.11 +		</form>
    2.12  	</body>
    2.13  </html>{{ end }}
     3.1 --- a/client.go	Wed Dec 17 22:27:44 2014 -0500
     3.2 +++ b/client.go	Sun Jan 04 00:07:27 2015 -0500
     3.3 @@ -1,8 +1,11 @@
     3.4  package auth
     3.5  
     3.6  import (
     3.7 +	"crypto/rand"
     3.8 +	"encoding/hex"
     3.9  	"encoding/json"
    3.10  	"errors"
    3.11 +	"github.com/gorilla/mux"
    3.12  	"net/http"
    3.13  	"net/url"
    3.14  	"time"
    3.15 @@ -313,3 +316,80 @@
    3.16  	defer m.endpointLock.RUnlock()
    3.17  	return int64(len(m.endpoints[client.String()])), nil
    3.18  }
    3.19 +
    3.20 +type newClientReq struct {
    3.21 +	Name      string   `json:"name"`
    3.22 +	Logo      string   `json:"logo"`
    3.23 +	Website   string   `json:"website"`
    3.24 +	Type      string   `json:"type"`
    3.25 +	Endpoints []string `json:"endpoints"`
    3.26 +}
    3.27 +
    3.28 +func RegisterClientHandlers(r *mux.Router, context Context) {
    3.29 +	r.Handle("/clients", wrap(context, CreateClientHandler)).Methods("POST")
    3.30 +}
    3.31 +
    3.32 +func CreateClientHandler(w http.ResponseWriter, r *http.Request, c Context) {
    3.33 +	username, password, ok := r.BasicAuth()
    3.34 +	if !ok {
    3.35 +		// TODO(paddy): return error
    3.36 +		return
    3.37 +	}
    3.38 +	profile, err := authenticate(username, password, c)
    3.39 +	if err != nil {
    3.40 +		// TODO(paddy): return error
    3.41 +		return
    3.42 +	}
    3.43 +	var req newClientReq
    3.44 +	decoder := json.NewDecoder(r.Body)
    3.45 +	err = decoder.Decode(&req)
    3.46 +	if err != nil {
    3.47 +		encode(w, r, http.StatusBadRequest, invalidFormatResponse)
    3.48 +		return
    3.49 +	}
    3.50 +	secret := make([]byte, 32)
    3.51 +	_, err = rand.Read(secret)
    3.52 +	if err != nil {
    3.53 +		// TODO(paddy): return error
    3.54 +		return
    3.55 +	}
    3.56 +	client := Client{
    3.57 +		ID:      uuid.NewID(),
    3.58 +		Secret:  hex.EncodeToString(secret),
    3.59 +		OwnerID: profile.ID,
    3.60 +		Name:    req.Name,
    3.61 +		Logo:    req.Logo,
    3.62 +		Website: req.Website,
    3.63 +		Type:    req.Type,
    3.64 +	}
    3.65 +	err = c.SaveClient(client)
    3.66 +	if err != nil {
    3.67 +		// TODO(paddy): return error
    3.68 +		return
    3.69 +	}
    3.70 +	endpoints := []Endpoint{}
    3.71 +	for _, u := range req.Endpoints {
    3.72 +		uri, err := url.Parse(u)
    3.73 +		if err != nil {
    3.74 +			// TODO(paddy): add error to response
    3.75 +			continue
    3.76 +		}
    3.77 +		endpoint := Endpoint{
    3.78 +			ID:       uuid.NewID(),
    3.79 +			ClientID: client.ID,
    3.80 +			URI:      *uri,
    3.81 +			Added:    time.Now(),
    3.82 +		}
    3.83 +		err = c.AddEndpoint(client.ID, endpoint)
    3.84 +		if err != nil {
    3.85 +			// TODO(paddy): return error
    3.86 +			return
    3.87 +		}
    3.88 +		endpoints = append(endpoints, endpoint)
    3.89 +	}
    3.90 +	resp := response{
    3.91 +		Clients:   []Client{client},
    3.92 +		Endpoints: endpoints,
    3.93 +	}
    3.94 +	encode(w, r, http.StatusCreated, resp)
    3.95 +}
     4.1 --- a/request.go	Wed Dec 17 22:27:44 2014 -0500
     4.2 +++ b/request.go	Sun Jan 04 00:07:27 2015 -0500
     4.3 @@ -28,9 +28,11 @@
     4.4  )
     4.5  
     4.6  type response struct {
     4.7 -	Errors   []requestError `json:"errors,omitempty"`
     4.8 -	Logins   []Login        `json:"logins,omitempty"`
     4.9 -	Profiles []Profile      `json:"profiles,omitempty"`
    4.10 +	Errors    []requestError `json:"errors,omitempty"`
    4.11 +	Logins    []Login        `json:"logins,omitempty"`
    4.12 +	Profiles  []Profile      `json:"profiles,omitempty"`
    4.13 +	Clients   []Client       `json:"clients,omitempty"`
    4.14 +	Endpoints []Endpoint     `json:"endpoints,omitempty"`
    4.15  }
    4.16  
    4.17  type requestError struct {