package freeipa import ( "crypto/tls" "encoding/json" "fmt" "io" "log" "net" "net/http" "os" "testing" "time" ) // Unused port for testing. const httpsPort = 8831 // Test login handler. func handleLogin(w http.ResponseWriter, req *http.Request) { // Logins are form data posts. req.ParseForm() // Check username/password equals test credentials. user := req.Form.Get("user") password := req.Form.Get("password") if user == "test" && password == "testpassword" { // Successful login send session cookie. cookie := http.Cookie{} cookie.Name = "ipa_session" cookie.Value = "correct-session-secret" cookie.Expires = time.Now().Add(30 * time.Minute) cookie.Secure = true cookie.HttpOnly = true cookie.Path = "/ipa" http.SetCookie(w, &cookie) w.Header().Set("IPASESSION", "correct-session-secret") } else { // Invalid login, send rejection. w.Header().Set("X-IPA-Rejection-Reason", "invalid-password") http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) fmt.Fprintf(w, `
kinit: Password incorrect while getting initial credentials
`) } } // Send JSON file to HTTP request. func sendJSONFile(w http.ResponseWriter, filePath string) { f, err := os.Open(filePath) if err != nil { log.Fatalln(err) } defer f.Close() io.Copy(w, f) } // General invalid json error response for testing error handling. func sendInvalidJSON(w http.ResponseWriter) { sendJSONFile(w, "test/invalid_json.json") } // Handle the json session test request. func handleJSON(w http.ResponseWriter, req *http.Request) { // If session cookie doesn't exist, something is wrong. Send unauthenticated response. cookie, err := req.Cookie("ipa_session") if err != nil || cookie.Value != "correct-session-secret" { http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) return } // Generally json response from here. w.Header().Set("Content-Type", "application/json") // Get the request body and parse it out. res := new(Request) err = json.NewDecoder(req.Body).Decode(res) if err != nil { // If the json decode fails, send the error. sendInvalidJSON(w) return } // For testing, we'll consider user_add/user_find as an accepted method, all others will error. if res.Method == "user_add" { // Send user add response data. sendJSONFile(w, "test/user_add_response.json") } else if res.Method == "user_find" { // Send user add response data. sendJSONFile(w, "test/user_find_response.json") } else { // An unexpected method received for testing, send error message. sendInvalidJSON(w) } } // General library tests with test server. func TestClient(t *testing.T) { // Spin up test server using port specified above. srvAddr := fmt.Sprintf("127.0.0.1:%d", httpsPort) http.HandleFunc("/ipa/session/login_password", handleLogin) http.HandleFunc("/ipa/session/json", handleJSON) isListening := make(chan bool) go func() { l, err := net.Listen("tcp", srvAddr) if err != nil { log.Fatal("Listen: ", err) } isListening <- true err = http.ServeTLS(l, nil, "test/cert.pem", "test/key.pem") if err != nil { log.Fatal("Serve: ", err) } }() // Allow the http server to initialize. <-isListening // Test server has a self signed certificate, ignore invalid certs. transportConfig := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } // Connect using wrong password to confirm invalid login responses are handled correctly. _, err := Connect(srvAddr, transportConfig, "test", "wrong-password") if err == nil || err.Error() != "login failed: unauthorized response