golang с fastcgi как читать REMOTE_USER

Коротко: как я могу прочитать переменную CGI REMOTE_USER на golang с помощью fastcgi?

Длинный: я пытаюсь написать программу для работы за httpd, используя fcgi через сокет. httpd выполняет завершение ssl и обеспечивает базовую аутентификацию. Мне нужно прочитать $REMOTE_USER, но я не могу в golang, а в perl могу.

Мой код основан на этом примере fcgi. . я пытаюсь

func homeView(w http.ResponseWriter, r *http.Request) {     
    user, pass, authok := r.BasicAuth()

Но authok всегда ложный, user и pass остаются пустыми, хотя я точно знаю, что авторизация (сделанная по httpd) прошла нормально. Чтобы устранить другие ошибки, я сделал это в perl:

my $socket = FCGI::OpenSocket("/run/fcgi-check.sock", 5);
my $q = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket);

while ($q->Accept() >= 0) {
    my $c = CGI::Simple->new;
    my $user_id      = $c->remote_user(); 

и он отлично работает в perl.

Для отладки я распечатал вывод r.Header и получил:

map[Authorization:[]

Я прав, что заголовок, который видит go, не содержит никакой информации о какой-либо авторизации? Но это происходит в Perl.

Вот полный, но минимальный пример кода golang, демонстрирующий проблему (в OpenBSD 5.8 с версией go go1.4.2 openbsd/amd64 и OpenBSD httpd с «аутентификацией «/» с ограниченными_пользователями» в httpd.conf.

package main

import (
        "github.com/gorilla/mux"
        "io"
        "log"
        "fmt"
        "net"
        "net/http"
        "net/http/fcgi"
)


func homeView(w http.ResponseWriter, r *http.Request) {
        headers := w.Header()
        headers.Add("Content-Type", "text/html")
        headers.Add("Cache-Control", "no-cache, no-store, must-revalidate")
        headers.Add("Pragma", "no-cache")
        headers.Add("Expires", "0")
        r.ParseForm()

        user, pass, authok := r.BasicAuth()

        if authok {
                io.WriteString(w, fmt.Sprintln("Auth OK"))
                io.WriteString(w, fmt.Sprintln("user is: "+user+", pass is: "+pass))
        } else {
                io.WriteString(w, fmt.Sprintln("Auth NOT OK"))
        }
}

func main() {

        r := mux.NewRouter()
        r.HandleFunc("/check/", homeView)

    var err error
        listener, err := net.Listen("unix", "/run/fcgi-check.sock")
        if err != nil {
                log.Fatal(err)
        }
        defer listener.Close()

        err = fcgi.Serve(listener, r)
        if err != nil { log.Fatal(err)}
}

Помощь будет оценена!

Заранее спасибо! Т.


person user208383    schedule 30.11.2015    source источник
comment
В вашем примере Perl используется переменная REMOTE_USER, но пример Go пытается выполнить BasicAuth. Вы проверили заголовки запросов для Remote-User (я совершенно уверен, что переменные CGI канонизируются и сопоставляются с заголовками)? Кроме того, почему вы вообще используете FCGI?   -  person JimB    schedule 01.12.2015
comment
Я не могу найти, как прочитать переменную окружения REMOTE_USER CGI в go (если r.BasicAuth() - неправильный способ сделать это). Как сказано в моем сообщении, я напечатал полные заголовки, используя io.WriteString(w, fmt.Sprintf("Header: %s", r.Header)), подтвердив, что карта Authorization:[] пуста и в этом заголовке нет REMOTE_USER. Я застрял. (И есть причины, которые я не могу обсуждать здесь, которые вынуждают меня использовать fcgi.)   -  person user208383    schedule 01.12.2015
comment
Ваша попытка использовать r.BasicAuth() неверна просто потому, что чтение CGI-переменной REMOTE_USER означает, что ожидается, что аутентификация будет выполняться веб-сервером, и вы не можете это контролировать. Итак, вам нужно просто правильно прочитать значение этой переменной. Я дал ответ, как это сделать.   -  person kostix    schedule 01.12.2015
comment
Не похоже, что REMOTE_USER используется в пакете fcgi. Я бы хотел, чтобы веб-сервер, выполняющий аутентификацию, поместил его в заголовок или переменную HTTP_REMOTE_USER.   -  person JimB    schedule 01.12.2015
comment
@JimB: Спасибо за разъяснения. Хотя изменение веб-сервера для решения проблемы на ходу не слишком привлекательно.   -  person user208383    schedule 02.12.2015
comment
Я не думаю, что это слишком большое дело. IIRC со времен CGI, у меня было несколько систем, которые использовали только HTTP_REMOTE_USER или какую-либо другую пользовательскую переменную. Назначение его после аутентификации было в порядке вещей.   -  person JimB    schedule 02.12.2015
comment
Go 1.9 сделает это: https://tip.golang.org/doc/go1.9#net/http/fcgi   -  person luca76    schedule 21.08.2017
comment
Вышла версия Go 1.9, и это действительно так.   -  person Gwyneth Llewelyn    schedule 12.09.2017


Ответы (4)


Go 1.9 будет предоставлять переменные окружения cgi. Как видно из этого закрытого билета:

https://go-review.googlesource.com/c/40012

person luca76    schedule 21.08.2017
comment
Go 1.9 вышел, и он действительно раскрывает REMOTE_USER. - person Gwyneth Llewelyn; 12.09.2017

Простой ответ (начиная с версии go 1.4.2) заключается в том, что в настоящее время go не поддерживает передачу CGI-переменной REMOTE_USER.

person user208383    schedule 02.12.2015
comment
Проверено с Go 1.5 под Linux/amd64, Apache2 2.4.10 + mod_fcgid + mod_auth_basic + mod_authz_user - person kostix; 02.12.2015

Хотя @JimB прав в том, что вы ошибаетесь в своем подходе, я отвечу на вопрос, как указано.

Пакет net/http/fcgi использует механизм net/http/cgi для заполнения экземпляра http.Request, который передается вашему обработчику, «параметрами» (парами ключ/значение), переданными веб-сервером во время сеанса FastCGI (вызова). Это делается здесь.

Теперь, если вы проверите соответствующий бит кода net/http/cgi , вы увидите, что переменные, которые не сопоставлены с определенными выделенными полями http.Request конвертировать в "заголовки" HTTP.

Это означает, что ваш код должен иметь доступ к нужной вам переменной, используя что-то вроде

ruser := r.Header.Get("Remote-User")

Обновление 2015-12-02: исследование, проведенное @JimB и OP, показало, что, по-видимому, невозможно прочитать переменную REMOTE_USER в FastCGI. Извините за шум.

person kostix    schedule 01.12.2015
comment
На самом деле, глядя сейчас на код cgi/fcgi, я не думаю, что REMOTE_USER вообще будет передан в запрос Go. В заголовки добавляются только несколько определенных переменных, и те, которые начинаются с HTTP_. - person JimB; 01.12.2015
comment
@kostix: я проверил и сфальсифицировал r.Header.Get("Remote-User"). Это не работает, по крайней мере, не в golang версии 1.4.2 (pgk OpenBSD 5.8). (Как я уже упоминал в своем исходном вопросе (Цитата: для отладки я распечатал вывод r.Header).) @JimB: Думаю, вы правы. Golang не передает REMOTE_USER в запрос на запуск. - person user208383; 02.12.2015
comment
@ user208383, очень плохо. Я бы посчитал это ошибкой. Извините, что ввел вас в заблуждение своим ответом. - person kostix; 02.12.2015

Это основное изменение пакета fcgi находится на рассмотрении и скоро будет объединено. Если это больше не актуально для вас, надеюсь, это будет полезно для других.

person lf215    schedule 13.04.2017