diff --git a/config.go b/config.go index dc20929..842abea 100644 --- a/config.go +++ b/config.go @@ -8,12 +8,13 @@ import ( ) type LdapConfig struct { - Url string - AdminUser string - UserAttr string - UserOu string - LdapDc string - LdapPass string + Url string + AdminUser string + UserAttr string + UserOu string + MineUserOu string + LdapDc string + LdapPass string } type MailConfig struct { @@ -64,6 +65,7 @@ func LoadConfig() (*Config, error) { l.AdminUser = viper.GetString("adminUser") l.UserAttr = viper.GetString("userAttr") l.UserOu = viper.GetString("userOu") + l.MineUserOu = viper.GetString("mineUserOu") l.LdapDc = viper.GetString("ldapDc") l.LdapPass = viper.GetString("ldapPass") c.Secret = viper.GetString("secret") diff --git a/ldap.go b/ldap.go index cf28bf6..1f9ad74 100644 --- a/ldap.go +++ b/ldap.go @@ -9,6 +9,34 @@ import ( "github.com/go-ldap/ldap" ) +func createLDAPMCAccount(uname, mcuname string) error { + if uname == "" || mcuname == "" { + log.Printf("error: missing field\n") + return errors.New("Missing field") + } + url := Conf.Ldap.Url + newdn := fmt.Sprintf("%v=%v,%v,%v", Conf.Ldap.UserAttr, mcuname, Conf.Ldap.MineUserOu, Conf.Ldap.LdapDc) + binddn := fmt.Sprintf("%v,%v", Conf.Ldap.AdminUser, Conf.Ldap.LdapDc) + maindn := fmt.Sprintf("%v=%v,%v,%v", Conf.Ldap.UserAttr, uname, Conf.Ldap.UserOu, Conf.Ldap.LdapDc) + l, err := ldap.DialURL(url) + if err != nil { + return err + } + defer l.Close() + err = l.Bind(binddn, Conf.Ldap.LdapPass) + if err != nil { + return err + } + addReq := ldap.NewAddRequest(newdn, []ldap.Control{}) + addReq.Attribute("objectClass", []string{"top", "account"}) + addReq.Attribute("seeAlso", []string{maindn}) + if err := l.Add(addReq); err != nil { + log.Printf("error adding service:", addReq, err) + return errors.New("Error creating LDAP account") + } + return nil +} + func createLDAPAccount(uname string, pwd string, email string) error { if uname == "" || pwd == "" || email == "" { log.Printf("error: missing field\n") @@ -167,7 +195,41 @@ func findLDAPAccountByEmail(email string) (string, error) { return entry.GetAttributeValue(Conf.Ldap.UserAttr), nil } - +func findLDAPMCAccount(uname string) (string, error) { + url := Conf.Ldap.Url + binddn := fmt.Sprintf("%v,%v", Conf.Ldap.AdminUser, Conf.Ldap.LdapDc) + basedn := fmt.Sprintf("%v,%v", Conf.Ldap.MineUserOu, Conf.Ldap.LdapDc) + userdn := fmt.Sprintf("%v=%v,%v,%v", Conf.Ldap.UserAttr, uname, Conf.Ldap.UserOu, Conf.Ldap.LdapDc) + l, err := ldap.DialURL(url) + if err != nil { + return "", err + } + defer l.Close() + err = l.Bind(binddn, Conf.Ldap.LdapPass) + if err != nil { + return "", err + } + result, err := l.Search(ldap.NewSearchRequest( + basedn, + ldap.ScopeWholeSubtree, + ldap.NeverDerefAliases, + 0, + 0, + false, + fmt.Sprintf("(&(objectClass=account)(seeAlso=%s))", userdn), + []string{"uid"}, + nil, + )) + if err != nil { + return "", err + } + if len(result.Entries) != 1 { + err_text := fmt.Sprintf("Error finding user: Wanted 1 result, got %v\n", len(result.Entries)) + return "", errors.New(err_text) + } + entry := result.Entries[0] + return entry.GetAttributeValue("uid"), nil +} func findLDAPAccountForDisplay(uname string) (User, error) { url := Conf.Ldap.Url binddn := fmt.Sprintf("%v,%v", Conf.Ldap.AdminUser, Conf.Ldap.LdapDc) diff --git a/main.go b/main.go index 68cb8df..c4893c4 100644 --- a/main.go +++ b/main.go @@ -29,6 +29,10 @@ func main() { router.HandleFunc("/profile/view", profilePage).Methods("GET") router.HandleFunc("/profile/edit", profileEditPage).Methods("GET") router.HandleFunc("/profile/edit", profileEdit).Methods("POST") + router.HandleFunc("/minecraft", minecraftPage).Methods("GET") + router.HandleFunc("/minecraft/link", minecraftLink).Methods("POST") + router.HandleFunc("/minecraft/link/success", minecraftLinkSuccessPage).Methods("GET") + router.HandleFunc("/minecraft/link/error", minecraftLinkErrorPage).Methods("GET") router.HandleFunc("/passwordreset", resetPageFront).Methods("GET") router.HandleFunc("/passwordreset", resetLookup).Methods("POST") router.HandleFunc("/passwordresetform", resetPageBack).Methods("GET") diff --git a/minecraft.go b/minecraft.go new file mode 100644 index 0000000..099f37b --- /dev/null +++ b/minecraft.go @@ -0,0 +1,28 @@ +package main + +import ( + "log" + "net/http" +) + +func minecraftLink(res http.ResponseWriter, req *http.Request) { + uname := getUserName(req) + if uname == "" { + http.Redirect(res, req, "/", 302) + } + mcname := req.FormValue("mcusername") + if mcname != "" { + log.Printf("linked MC %v to LDAP %v\n", mcname, uname) + err := createLDAPMCAccount(uname, mcname) + if err != nil { + log.Printf("Error linking MC account: %v\n", err) + http.Redirect(res, req, "/minecraft/link/error", 302) + } else { + http.Redirect(res, req, "/minecraft/link/success", 302) + } + } else { + log.Println("couldn't get MC username") + http.Redirect(res, req, "/minecraft/link/error", 302) + } + return +} diff --git a/templates/index.html b/templates/index.html index 5d07428..8b295c9 100644 --- a/templates/index.html +++ b/templates/index.html @@ -3,6 +3,7 @@ {{if .LoggedIn }}

Get Token

Profile

+

Minecraft Account Status

{{else}}

Register

Reset Password

diff --git a/templates/minecraft.html b/templates/minecraft.html new file mode 100644 index 0000000..6f94616 --- /dev/null +++ b/templates/minecraft.html @@ -0,0 +1,24 @@ +{{ define "minecraft" }} +{{ template "header" .}} + +
+ {{if .Linked }} +

Your Minecraft Account {{ .MinecraftAccount }} is linked with {{ .Username }}.

+ {{ else }} +
+

Enter your Minecraft Username and click the button to link it to your Saintnet account.

+

This will add you to any connected servers whitelist

+ + + + + + + +
Minecraft Username:
+
+
+ {{end}} +
+{{template "footer" .}} +{{end}} diff --git a/templates/minecraft_error.html b/templates/minecraft_error.html new file mode 100644 index 0000000..bb47697 --- /dev/null +++ b/templates/minecraft_error.html @@ -0,0 +1,8 @@ +{{ define "minecraft_error" }} +{{ template "header" .}} +

Unable to link your Minecraft account due to the following error:

+

{{.Error}}

+

Please try again or let the admin know.

+

Return to homepage

+{{template "footer" .}} +{{ end }} diff --git a/templates/minecraft_success.html b/templates/minecraft_success.html new file mode 100644 index 0000000..d774db1 --- /dev/null +++ b/templates/minecraft_success.html @@ -0,0 +1,6 @@ +{{ define "minecraft_success" }} +{{ template "header" .}} +

Your Minecraft account has been linked

+

Return to homepage

+{{template "footer" .}} +{{ end }} diff --git a/web.go b/web.go index eaac6c4..d002df9 100644 --- a/web.go +++ b/web.go @@ -55,6 +55,65 @@ func profileEditPage(res http.ResponseWriter, req *http.Request) { } tpl.ExecuteTemplate(res, "profile_edit", data) } + +func minecraftPage(res http.ResponseWriter, req *http.Request) { + log.Println("GET /minecraft") + u := getUserName(req) + if u == "" { + http.Redirect(res, req, "/", 302) + } else { + mcuser, err := findLDAPMCAccount(u) + mclink := true + if err != nil { + mclink = false + mcuser = "N/A" + } + data := struct { + Title string + Username string + LoggedIn bool + Linked bool + MinecraftAccount string + }{ + "Link Minecraft Account", + u, + true, + mclink, + mcuser, + } + tpl.ExecuteTemplate(res, "minecraft", data) + } +} +func minecraftLinkSuccessPage(res http.ResponseWriter, req *http.Request) { + log.Println("GET /minecraft/link/success") + data := struct { + Title string + Username string + LoggedIn bool + }{ + "Minecraft Link Success", + "", + true, + } + tpl.ExecuteTemplate(res, "minecraft_success", data) + return +} +func minecraftLinkErrorPage(res http.ResponseWriter, req *http.Request) { + log.Println("GET /minecraft/link/error") + data := struct { + Title string + Username string + LoggedIn bool + Error string + }{ + "Minecraft Link Failure", + "", + true, + "Undefined", + } + tpl.ExecuteTemplate(res, "minecraft_error", data) + return +} func resetPageFront(res http.ResponseWriter, req *http.Request) { log.Println("GET /passwordreset") u := getUserName(req)