Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Hirsch committed Jul 14, 2013
0 parents commit 721ed47
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*~
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Revel Persona module
====================

To use:

Reference in app.conf:

module.persona = gopkg.upstandinghackers.com/revel/modules/persona

[dev]
persona.audience = http://localhost:9000

[prod]
persona.audience = <insert URL here>

And at the top of your `routes`:

module:persona

Then, wire it into your controller

type AppController {
*revel.Controller
persona.Persona
}

func (c *AppController) Index() revel.Result {
if c.UserEmail != nil {
// logged in user
}
}
99 changes: 99 additions & 0 deletions app/controllers/persona.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package controllers

import (
"encoding/json"
"github.com/robfig/revel"
"net/http"
"net/url"
"strconv"
)

var audience string

type Persona struct {
*revel.Controller
UserEmail *string
}

type personaResponse struct {
Status string `json:"status"`
Email *string `json:"email,omitempty"`
Audience *string `json:"audience,omitempty"`
Expires *int64 `json:"expires,omitempty"`
Issuer *string `json:"issuer,omitempty"`
Reason *string `json:"reason,omitempty"`
}

type ErrorString string
func (s ErrorString) Error() string {
return string(s)
}

func (c Persona) Login(assertion string, redirect string) revel.Result {
resp, err := http.PostForm("https://verifier.login.persona.org/verify", url.Values{
"assertion": {assertion},
"audience": {audience},
})
if err != nil {
revel.WARN.Fatal("Failed to verify assertion: %s", err)
return c.RenderError(err)
}
defer resp.Body.Close()
decoder := json.NewDecoder(resp.Body)
pr := personaResponse{}
if err := decoder.Decode(&pr); err != nil {
revel.WARN.Fatal("Failed to decode JSON")
}
if pr.Status == "okay" {
c.Session["persona/email"] = *pr.Email
c.Session["persona/exp"] = strconv.FormatInt(*pr.Expires, 36)
if redirect == "" {
return c.Render(pr)
}
return c.Redirect(redirect)
}
return c.RenderError(ErrorString(*pr.Reason))
}

func (c Persona) Logout(redirect string) revel.Result {
delete(c.Session, "persona/email")
delete(c.Session, "persona/exp")
if redirect != "" {
return c.Redirect(redirect)
}
return c.RenderText("Logged out")
}

func (p *Persona) CheckUser() revel.Result {
var ok bool
var exp, email string
if exp, ok = p.Session["persona/exp"]; !ok {
return nil
}
if email, ok = p.Session["persona/email"]; !ok {
return nil
}

if expms, err := strconv.ParseInt(exp); err != nil {
revel.ERROR.Fatal("Failed to parse expiration: %s", err)
} else {
expt := time.Unix(expms / 1000, (expms % 1000) * 1000000)
if expt.Before(time.Now()) {
p.Logout()
return nil
}
}
p.UserEmail = email
return nil
}

func init() {
revel.OnAppStart(func() {
var found bool
if audience, found = revel.Config.String("persona.audience"); !found {
revel.ERROR.Fatal("No persona.audience found")
}
})

revel.InterceptMethod((*Persona).CheckUser, revel.BEFORE)
}
2 changes: 2 additions & 0 deletions conf/routes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
POST /persona/login Persona.Login
GET /persona/login Persona.Login

0 comments on commit 721ed47

Please sign in to comment.