aboutsummaryrefslogblamecommitdiff
path: root/api.go
blob: bce99939ec6ff702e16606bb688c52898ceec839 (plain) (tree)
1
2
3
4
5
6
7



                   
                
             
                                                                     






                                    
                                                                                  



                                                                                               
                                                                                        












                                                                                      
                                                                        





                                                                                               
                                                                                                          

































                                                                                      
                                                                                                              




                                                                                      
                                                                                                                                     


















                                                                                                                   









                                                                                                        


                                                                    
                                                     



                                
 




























                                                                                                                     
                                 


              
package main

import (
	//"context"
	"errors"
	"fmt"
	garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang"
	"github.com/go-ldap/ldap/v3"
	//"github.com/gorilla/mux"
	"log"
	"net/http"
	"strings"
)

func checkLoginAPI(w http.ResponseWriter, r *http.Request) (*LoginStatus, error) {
	username, password, ok := r.BasicAuth()
	if !ok {
		w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return nil, errors.New("Missing or invalid 'Authenticate: Basic' field")
	}
	user_dn := buildUserDN(username)

	login_info := &LoginInfo{
		DN:       user_dn,
		Username: username,
		Password: password,
	}

	l := ldapOpen(w)
	if l == nil {
		log.Println(l)
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return nil, errors.New("Unable to open LDAP connection")
	}

	err := l.Bind(login_info.DN, login_info.Password)
	if err != nil {
		w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return nil, errors.New("Unable to bind this user+password combination on the LDAP server")
	}

	loginStatus := &LoginStatus{
		Info: login_info,
		conn: l,
	}

	requestKind := "(objectClass=organizationalPerson)"

	if strings.EqualFold(login_info.DN, config.AdminAccount) {
		requestKind = "(objectclass=*)"
	}
	searchRequest := ldap.NewSearchRequest(
		login_info.DN,
		ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false,
		requestKind,
		[]string{
			"dn",
			"displayname",
			"givenname",
			"sn",
			"mail",
			"memberof",
			"description",
			"garage_s3_access_key",
			FIELD_NAME_DIRECTORY_VISIBILITY,
			FIELD_NAME_PROFILE_PICTURE,
		},
		nil)

	sr, err := l.Search(searchRequest)
	if err != nil {
		log.Println(err)
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return nil, errors.New("Unable to search essential information about the logged user on LDAP")
	}

	if len(sr.Entries) != 1 {
		log.Println(fmt.Sprintf("Unable to find entry for %s", login_info.DN))
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return nil, errors.New("Not enough or too many entries for this user in the LDAP directory (expect a unique result)")
	}

	loginStatus.UserEntry = sr.Entries[0]

	loginStatus.CanAdmin = strings.EqualFold(loginStatus.Info.DN, config.AdminAccount)
	loginStatus.CanInvite = false
	for _, attr := range loginStatus.UserEntry.Attributes {
		if strings.EqualFold(attr.Name, "memberof") {
			for _, group := range attr.Values {
				if config.GroupCanInvite != "" && strings.EqualFold(group, config.GroupCanInvite) {
					loginStatus.CanInvite = true
				}
				if config.GroupCanAdmin != "" && strings.EqualFold(group, config.GroupCanAdmin) {
					loginStatus.CanAdmin = true
				}
			}
		}
	}

	return loginStatus, nil
}

func checkLoginAndS3API(w http.ResponseWriter, r *http.Request) (*LoginStatus, *garage.KeyInfo, error) {
	login, err := checkLoginAPI(w, r)
	if err != nil {
		return nil, nil, err
	}
	keyPair, err := checkS3(login)
	return login, keyPair, err
}

func handleAPIGarageBucket(w http.ResponseWriter, r *http.Request) {
	login, s3key, err := checkLoginAndS3API(w, r)
	if err != nil {
		log.Println(err)
		return
	}

	// CHECK PATCH REQUEST

	// READ BODY JSON

	// VALIDATE OBJECT
	// --- bucket query parameter ---
	// 1. bucket must be owned by the key with owner permission, otherwise throw "unauthorized" (401)
	// 2. must not end with deuxfleurs.fr or deuxfleurs.org, otherwise throw "forbidden" (403)
	// --- global ---
	// 1. can be true, false, or nil (use pointers)
	// 2. if nil do nothing
	// 3. if false, throw "not yet implemented" (501)
	// 4. if true, check that the bucket name does not exist yet in the global namespace, throw "forbidden" (403)
	// --- quota.size ---
	// 1. if no quota on the bucket + this field is none, set to 50MB
	// 2. if lower than 50MB, set to 50MB. If higher than 200MB, set to 200MB
	// --- quota.files ---
	// 1. if no quota on the bucket + this field is none, set to 10k
	// 2. if lower than 10k, set to 10k. If higher than 40k, set to 40k

	// IF BODY.GLOBAL is not NONE
	// Add an alias

	// IF BODY.QUOTA.SIZE is not NONE
	// Change quota

	// IF BODY.QUOTA.FILE is not NONE
	// Change quota

	log.Println(login, s3key)

	return
}