Replace map[string]interface{} with map[string]any, ioutil.ReadAll with
io.ReadAll, and simplify redundant fmt.Sprintf/w.Write calls.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
131 lines
4.2 KiB
Go
131 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"html"
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/go-ldap/ldap/v3"
|
|
)
|
|
|
|
func login(login string, password string) ([]*ldap.EntryAttribute, error) {
|
|
conn, err := myLDAP.Connect()
|
|
if err != nil || conn == nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err = conn.ServiceBind(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var dn string
|
|
dn, err = conn.SearchDN(login, true)
|
|
if err != nil {
|
|
dn, err = conn.SearchDN(login, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if err := conn.Bind(dn, password); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if entries, err := conn.GetEntry(dn); err != nil {
|
|
return nil, err
|
|
} else {
|
|
return entries, nil
|
|
}
|
|
}
|
|
|
|
func tryLogin(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != "POST" {
|
|
displayTmpl(w, "login.html", map[string]any{})
|
|
return
|
|
}
|
|
|
|
if !authLimiter.Allow(remoteIP(r)) {
|
|
displayTmplError(w, http.StatusTooManyRequests, "login.html", map[string]any{"error": "Too many login attempts. Please try again later."})
|
|
return
|
|
}
|
|
|
|
if !validateAltcha(r) {
|
|
displayTmplError(w, http.StatusForbidden, "login.html", map[string]any{"error": "Invalid or missing altcha response. Please try again."})
|
|
return
|
|
}
|
|
|
|
if entries, err := login(r.PostFormValue("login"), r.PostFormValue("password")); err != nil {
|
|
log.Println(err)
|
|
displayTmplError(w, http.StatusInternalServerError, "login.html", map[string]any{"error": err.Error()})
|
|
} else {
|
|
apiToken := AddyAPIToken(r.PostFormValue("login"))
|
|
|
|
cnt := "<ul>"
|
|
for _, e := range entries {
|
|
for i, v := range e.Values {
|
|
safeName := html.EscapeString(e.Name)
|
|
safeVal := html.EscapeString(v)
|
|
elemID := fmt.Sprintf("mailAlias-%d", i)
|
|
if e.Name == "userPassword" || e.Name == "krbPrincipalKey" {
|
|
cnt += "<li><strong>" + safeName + ":</strong> <em>[...]</em></li>"
|
|
} else if e.Name == "mailAlias" && len(strings.SplitN(v, "@", 2)[0]) == 10 {
|
|
safeURL := url.PathEscape(v)
|
|
safeToken := html.EscapeString(apiToken)
|
|
safeElemID := html.EscapeString(elemID)
|
|
cnt += `<li id="` + safeElemID + `"><strong>` + safeName + `:</strong> ` + safeVal +
|
|
`<button type="button" class="mx-1 btn btn-sm btn-danger" data-alias="` + safeURL + `" data-token="` + safeToken + `" data-elem="` + safeElemID + `" onclick="(function(b){fetch('/api/v1/aliases/'+b.dataset.alias,{'method':'delete','headers':{'Authorization':'Bearer '+b.dataset.token}}).then(function(r){if(r.ok)document.getElementById(b.dataset.elem).remove();})})(this)">Supprimer</button></li>`
|
|
} else {
|
|
cnt += "<li><strong>" + safeName + ":</strong> " + safeVal + "</li>"
|
|
}
|
|
}
|
|
}
|
|
displayTmpl(w, "message.html", map[string]any{"details": template.HTML(`Login ok<br><br>Here are the information we have about you:` + cnt + "</ul><p>To use our Addy.io compatible API, use the following token: <code>" + html.EscapeString(apiToken) + "</code></p>")})
|
|
}
|
|
}
|
|
|
|
func httpBasicAuth(w http.ResponseWriter, r *http.Request) {
|
|
if !authLimiter.Allow(remoteIP(r)) {
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="nemunai.re restricted"`)
|
|
w.WriteHeader(http.StatusTooManyRequests)
|
|
w.Write([]byte("Too many requests"))
|
|
return
|
|
}
|
|
|
|
if user, pass, ok := r.BasicAuth(); ok {
|
|
if entries, err := login(user, pass); err != nil {
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="nemunai.re restricted"`)
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
} else {
|
|
w.Header().Set("X-Remote-User", user)
|
|
w.WriteHeader(http.StatusOK)
|
|
for _, e := range entries {
|
|
for _, v := range e.Values {
|
|
if e.Name != "userPassword" {
|
|
fmt.Fprintf(w, "%s: %s", e.Name, v)
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
} else if dockerRegistrySecret != "" && r.Header.Get("X-Special-Auth") == dockerRegistrySecret {
|
|
method := r.Header.Get("X-Original-Method")
|
|
uri := r.Header.Get("X-Original-URI")
|
|
|
|
if (method == "GET" || method == "HEAD") && uri != "" && uri != "/" && uri != "/v2/" && !strings.HasPrefix(uri, "/v2/_") {
|
|
log.Printf("docker-registry: Permit anonymous login for URL %s", uri)
|
|
w.Header().Set("X-Remote-User", "anonymous")
|
|
w.WriteHeader(http.StatusOK)
|
|
return
|
|
}
|
|
}
|
|
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="nemunai.re restricted"`)
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
w.Write([]byte("Please login"))
|
|
}
|