Skip to content

Commit

Permalink
Update to use echo and CORs actually works this time
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisseto committed Jul 14, 2015
1 parent bd5e1e3 commit aa1235a
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 146 deletions.
167 changes: 21 additions & 146 deletions fakecas.go
Original file line number Diff line number Diff line change
@@ -1,168 +1,43 @@
package main

import (
"encoding/json"
"encoding/xml"
"flag"
"fmt"
"github.com/labstack/echo"
mw "github.com/labstack/echo/middleware"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"log"
"net/http"
"net/url"
"strings"
)

type OAuthAttributes struct {
LastName string `json:"lastName"`
FirstName string `json:"firstName"`
}

type OAuthResponse struct {
Id string `json:"id"`
Attributes OAuthAttributes `json:"attributes"`
}

type User struct {
Id string `bson:"_id"`
Username string `bson:"username"`
Emails []string `bson:"emails"`
Fullname string `bson:"fullname"`
GivenName string `bson:"given_name"`
FamilyName string `bson:"family_name"`
}

type ServiceResponse struct {
Xmlns string `xml:"xmlns:cas,attr"`
XMLName xml.Name `xml:"cas:serviceResponse"`
User string `xml:"cas:authenticationSuccess>cas:user"`
NewLogin bool `xml:"cas:authenticationSuccess>cas:attributes>cas:isFromNewLogin"`
Date string `xml:"cas:authenticationSuccess>cas:attributes>cas:authenticationDate"`
GivenName string `xml:"cas:authenticationSuccess>cas:attributes>cas:givenName"`
FamilyName string `xml:"cas:authenticationSuccess>cas:attributes>cas:familyName"`
LongTermAuth bool `xml:"cas:authenticationSuccess>cas:attributes>cas:longTermAuthenticationRequestTokenUsed"`
AccessToken string `xml:"cas:authenticationSuccess>cas:attributes>accessToken"`
UserName string `xml:"cas:authenticationSuccess>cas:attributes>username"`
}

var (
host = flag.String("host", "localhost:8080", "The host to bind to")
databasename = flag.String("dbname", "osf20130903", "The name of your OSF database")
databaseaddress = flag.String("dbaddress", "localhost:27017", "The address of your mongodb. ie: localhost:27017")
Host = flag.String("host", "localhost:8080", "The host to bind to")
DatabaseName = flag.String("dbname", "osf20130903", "The name of your OSF database")
DatabaseAddress = flag.String("dbaddress", "localhost:27017", "The address of your mongodb. ie: localhost:27017")
DatabaseSession mgo.Session
UserCollection *mgo.Collection
)

func main() {
flag.Parse()
e := echo.New()
e.Use(mw.Logger())
e.Use(mw.Recover())
e.Use(CorsMiddleWare())

http.HandleFunc("/login", login)
http.HandleFunc("/logout", logout)
http.HandleFunc("/oauth2/profile", oauth)
http.HandleFunc("/p3/serviceValidate", serviceValidate)

fmt.Println("Expecting database", *databasename, " to be running at", *databaseaddress)
fmt.Println("Listening on", *host)
e.Post("/login", Login)
e.Get("/logout", Logout)
e.Get("/oauth2/profile", OAuth)
e.Get("/p3/serviceValidate", ServiceValidate)

err := http.ListenAndServe(*host, nil)
fmt.Println("Expecting database", *DatabaseName, " to be running at", *DatabaseAddress)
fmt.Println("Listening on", *Host)

if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

func login(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Access-Control-Allow-Origin", "*")
redir, err := url.Parse(r.FormValue("service"))

if err != nil {
log.Fatal(err)
}

query := redir.Query()
query.Set("ticket", r.FormValue("username"))
redir.RawQuery = query.Encode()

fmt.Println("Logging in and redirecting to", redir)
http.Redirect(w, r, redir.String(), http.StatusFound)
}

func logout(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Access-Control-Allow-Origin", "*")
fmt.Println("Logging out and redirecting to", r.FormValue("service"))
http.Redirect(w, r, r.FormValue("service"), http.StatusFound)
}

func serviceValidate(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Access-Control-Allow-Origin", "*")

session, err := mgo.Dial(*databaseaddress)
DatabaseSession, err := mgo.Dial(*DatabaseAddress)
if err != nil {
panic(err)
}
defer session.Close()

c := session.DB(*databasename).C("user")

result := User{}
err = c.Find(bson.M{"emails": r.FormValue("ticket")}).One(&result)
defer DatabaseSession.Close()

if err != nil {
fmt.Println("User", r.FormValue("ticket"), "not found.")
http.NotFound(w, r)
return
}

response := ServiceResponse{
Xmlns: "http://www.yale.edu/tp/cas",
User: result.Id,
NewLogin: true,
Date: "Eh",
GivenName: result.GivenName,
FamilyName: result.FamilyName,
AccessToken: result.Id,
UserName: result.Username,
}

x, err := xml.MarshalIndent(response, "", " ")
if err != nil {
panic(err)
}

w.Header().Set("Content-Type", "application/xml")
w.Write(x)
}

func oauth(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Access-Control-Allow-Origin", "*")

session, err := mgo.Dial(*databaseaddress)
if err != nil {
panic(err)
}
defer session.Close()

c := session.DB(*databasename).C("user")

result := User{}
err = c.Find(bson.M{"_id": strings.Replace(r.Header.Get("Authorization"), "Bearer ", "", 1)}).One(&result)

if err != nil {
http.NotFound(w, r)
return
}

js, err := json.Marshal(OAuthResponse{
Id: result.Id,
Attributes: OAuthAttributes{
LastName: result.FamilyName,
FirstName: result.GivenName,
},
})

if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
UserCollection = DatabaseSession.DB(*DatabaseName).C("user")

w.Header().Set("Content-Type", "application/json")
w.Write(js)
e.Run(*Host)
}
21 changes: 21 additions & 0 deletions middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package main

import "github.com/labstack/echo"

func CorsMiddleWare() echo.MiddlewareFunc {
return func(h echo.HandlerFunc) echo.HandlerFunc {
return func(c *echo.Context) error {
c.Response().Header().Add("Access-Control-Allow-Origin", "*")
c.Response().Header().Add("Access-Control-Allow-Headers", "Range, Content-Type, Authorization, Cache-Control, X-Requested-With")
c.Response().Header().Add("Access-Control-Expose-Headers", "Range, Content-Type, Authorization, Cache-Control, X-Requested-With")
c.Response().Header().Add("Cache-control", "no-store, no-cache, must-revalidate, max-age=0")

if c.Request().Method == "OPTIONS" {
c.Response().Header().Add("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE")
return c.NoContent(204)
}
h(c)
return nil
}
}
}
35 changes: 35 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import "encoding/xml"

type OAuthAttributes struct {
LastName string `json:"lastName"`
FirstName string `json:"firstName"`
}

type OAuthResponse struct {
Id string `json:"id"`
Attributes OAuthAttributes `json:"attributes"`
}

type User struct {
Id string `bson:"_id"`
Username string `bson:"username"`
Emails []string `bson:"emails"`
Fullname string `bson:"fullname"`
GivenName string `bson:"given_name"`
FamilyName string `bson:"family_name"`
}

type ServiceResponse struct {
Xmlns string `xml:"xmlns:cas,attr"`
XMLName xml.Name `xml:"cas:serviceResponse"`
User string `xml:"cas:authenticationSuccess>cas:user"`
NewLogin bool `xml:"cas:authenticationSuccess>cas:attributes>cas:isFromNewLogin"`
Date string `xml:"cas:authenticationSuccess>cas:attributes>cas:authenticationDate"`
GivenName string `xml:"cas:authenticationSuccess>cas:attributes>cas:givenName"`
FamilyName string `xml:"cas:authenticationSuccess>cas:attributes>cas:familyName"`
LongTermAuth bool `xml:"cas:authenticationSuccess>cas:attributes>cas:longTermAuthenticationRequestTokenUsed"`
AccessToken string `xml:"cas:authenticationSuccess>cas:attributes>accessToken"`
UserName string `xml:"cas:authenticationSuccess>cas:attributes>username"`
}
75 changes: 75 additions & 0 deletions views.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

import (
"fmt"
"github.com/labstack/echo"
"gopkg.in/mgo.v2/bson"
"net/http"
"net/url"
"strings"
)

func Login(c *echo.Context) error {
redir, err := url.Parse(c.Form("service"))

if err != nil {
c.Error(err)
return nil
}

query := redir.Query()
query.Set("ticket", c.Form("username"))
redir.RawQuery = query.Encode()

fmt.Println("Logging in and redirecting to", redir)
c.Redirect(http.StatusFound, redir.String())
return nil
}

func Logout(c *echo.Context) error {
fmt.Println("Logging out and redirecting to", c.Form("service"))
c.Redirect(http.StatusFound, c.Form("service"))
return nil
}

func ServiceValidate(c *echo.Context) error {
result := User{}
err := UserCollection.Find(bson.M{"emails": c.Form("ticket")}).One(&result)

if err != nil {
fmt.Println("User", c.Form("ticket"), "not found.")
return c.NoContent(http.StatusNotFound)
}

response := ServiceResponse{
Xmlns: "http://www.yale.edu/tp/cas",
User: result.Id,
NewLogin: true,
Date: "Eh",
GivenName: result.GivenName,
FamilyName: result.FamilyName,
AccessToken: result.Id,
UserName: result.Username,
}

return c.XML(http.StatusOK, response)
}

func OAuth(c *echo.Context) error {
result := User{}
err := UserCollection.Find(bson.M{
"_id": strings.Replace(c.Request().Header.Get("Authorization"), "Bearer ", "", 1),
}).One(&result)

if err != nil {
return c.NoContent(http.StatusNotFound)
}

return c.JSON(200, OAuthResponse{
Id: result.Id,
Attributes: OAuthAttributes{
LastName: result.FamilyName,
FirstName: result.GivenName,
},
})
}

0 comments on commit aa1235a

Please sign in to comment.