使用cURL以用户名和密码登录Gitlab
为了针对Docker中的Gitlab实例测试命令行工具,我想使用用户名和密码登录Gitlab,并获取创建的会话来验证我的API请求 因此,我采取以下行动:使用cURL以用户名和密码登录Gitlab,curl,gitlab,csrf,Curl,Gitlab,Csrf,为了针对Docker中的Gitlab实例测试命令行工具,我想使用用户名和密码登录Gitlab,并获取创建的会话来验证我的API请求 因此,我采取以下行动: 使用curl-i卷曲用户登录页面http://localhost:8080/users/sign_in -s 从标题中获取\u gitlab\u会话 从登录表单中获取authenticity\u令牌 使用发送第二个curl请求 但是我得到的不是有效的用户登录,而是 422 - The change you requested was reje
curl-i卷曲用户登录页面http://localhost:8080/users/sign_in -s
\u gitlab\u会话
authenticity\u令牌
422 - The change you requested was rejected.
在日志文件里,我明白了
==> gitlab-rails/production.log <==
Started POST "/users/sign_in" for 172.17.0.1 at 2017-12-23 00:22:16 +0000
Processing by SessionsController#create as HTML
Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"login"=>"root", "password"=>"[FILTERED]", "remember_me"=>"0"}}
Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 125ms (ActiveRecord: 7.8ms)
==> gitlab-rails/production_json.log <==
{"method":"POST","path":"/users/sign_in","format":"html","controller":"SessionsController",
"action":"create","status":422,"error":"
ActionController::InvalidAuthenticityToken:ActionController::InvalidAuthenticityToken",
"duration":126.29,"view":0.0,"db":7.78,"time":"2017-12-23T00:22:16.039Z",
"params":{"authenticity_token":"[FILTERED]","user":{"login":"root","password":"
[FILTERED]","remember_me":"0"}},"remote_ip":"172.17.0.1",
"user_id":1,"username":"root"}
==> gitlab-rails/production.log <==
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
lib/gitlab/middleware/multipart.rb:93:in `call'
lib/gitlab/request_profiler/middleware.rb:14:in `call'
lib/gitlab/middleware/go.rb:18:in `call'
lib/gitlab/etag_caching/middleware.rb:11:in `call'
lib/gitlab/middleware/read_only.rb:31:in `call'
lib/gitlab/request_context.rb:18:in `call'
lib/gitlab/metrics/requests_rack_middleware.rb:27:in `call'
==>gitlab rails/production.log“[过滤]”,“用户”=>{“登录”=>“根”,“密码”=>“[过滤],“记住我”=>“0”}
无法验证CSRF令牌的真实性
在125ms内完成422个无法处理的实体(ActiveRecord:7.8ms)
==>gitlab rails/production\u json.log gitlab rails/production.log确切地说,${cookie}
中是什么?在我的测试中,登录页面中有4个cookie,其中3个看起来像令牌,如果成功登录至少还需要1个cookie,而不是\u gitlab\u session
cookie,我也不会感到惊讶。但与其费心寻找所需cookie的正确组合,不如让curl自动处理cookie,例如--cookie jar
和--cookie
(那么所有cookie都应该是正确的)-此外,登录页面上有3个不同的真实性标记,你确定你拿的是正确的吗?也许你的问题是取错了令牌。区分这3个标记非常困难,因此我建议改用脚本语言
下面是一个使用PHP的测试工作示例(只需替换第10行和第11行的用户名和密码):
通过其他答案和评论,我终于想出了以下解决方案:
gitlab\u主机=”http://localhost:8080"
gitlab_user=“root”
gitlab_password=“12341234”
#curl用于登录页面,以获取会话cookie和带有auth令牌的源
body_header=$(curl-c cookies.txt-i“${gitlab_host}/users/sign_-in“-s)
#grep的用户登录的身份验证令牌
#不确定页面上的另一个令牌是否也会起作用-共有3个令牌
csrf_token=$(echo$body_header | perl-ne'print“$1\n”if/new_user.*?authenticity_token”[[:blank:]value=“(.+?)”/”| sed-n 1p)
#使用以前请求中的cookie和令牌,使用curl发送登录凭据
curl-b cookies.txt-c cookies.txt-i“${gitlab\u host}/users/sign\u-in”\
--数据“用户[登录]=${gitlab\u用户}和用户[密码]=${gitlab\u密码}”\
--数据urlencode“真实性\u令牌=${csrf\u令牌}”
#将curl GET请求发送到个人访问令牌页以获取身份验证令牌
body_header=$(curl-H'user-agent:curl'-b cookies.txt-i“${gitlab_-host}/profile/personal_-access_-tokens”-s)
csrf_-token=$(echo$body_-header | perl-ne'print“$1\n”if/authenticity_-token”[[:blank:]value=“(.+?)”/”;sed-n 1p)
#curl POST发送“生成个人访问令牌表单”的请求
#响应将是重定向,因此我们必须使用“-L`
body_header=$(curl-L-bcookies.txt“${gitlab_host}/profile/personal_access_tokens”\
--数据urlencode“真实性\u令牌=${csrf\u令牌}”\
--数据'personal_access_token[name]=golab生成的和personal_access_token[expires_at]=&personal_access_token[scopes][]=api')
#从响应HTML中刮取个人访问令牌
personal_access_token=$(echo$body_header | perl-ne'print“$1\n”if/created personal access token”[[:blank:]value=“(.+?)”/”;sed-n 1p)
根据,您现在可以使用会话cookie对API请求进行身份验证:
curl——标题“私有令牌:${personal\u access\u Token}”https://gitlab.example.com/api/v4/projects
一些提示:
- 我首先混淆了
curl-c文件
(从标题中读取cookies并将其写入文件)和curl-b文件
(使用文件中的cookies并随请求发送cookies)
- 不幸的是,我没有找到与
sed
一起工作的正则表达式,因此我不得不在这里使用perl
- 在Chrome中使用开发者控制台并将
POST
请求复制为curl命令非常有用:
在gitlab中创建访问令牌或私有令牌,您可以在URL中使用它
bash我得到了一个使用Python的稳定版本,并且:
从urllib.parse导入urljoin
导入请求
进口bs4
基本的http://gitlab.example.com/'
用户名='me'
密码='让我进来'
#使用会话,以便在请求之间保留cookie。
会话=请求。会话()
#加载登录页面以获取CSRF令牌。
response=session.get(urljoin(基本uri,'users/sign_-in'))
响应。针对_状态()提出_
#从登录页面提取CSRF令牌。
soup=bs4.BeautifulSoup(response.text'html.parser')
csrf_param=soup.find('meta',dict(name='csrf-param'))['content']
csrf_token=soup.find('meta',dict(name='csrf-token'))['content']
#登录。
请求\u数据={
“用户名”:用户名,
“密码”:密码,
csrf_参数:csrf_令牌}
response=session.post(response.url,data=request\u data)
响应。针对_状态()提出_
#获取项目列表。
response=session.get(urljoin(基本uri,'api/v4/projects'))
打印(response.json())
错误是说您的CSRF(真实性)令牌无效。您能再次检查是否正确提取它吗?再次检查后,您能尝试使用cookie jar吗?而不是手动包含标头?此脚本可能会启发您:(关于的完整讨论)虽然这个答案很可能是正确的,但我不能在我的案例中使用PHP。无论如何:感谢您提供了全面的答案!请参阅下面我的帖子,我最终是如何使用bash/perl解决的。@MichaelLihs perl应该完全能够做到这一点:)(编辑:现在我可以
==> gitlab-rails/production.log <==
Started POST "/users/sign_in" for 172.17.0.1 at 2017-12-23 00:22:16 +0000
Processing by SessionsController#create as HTML
Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"login"=>"root", "password"=>"[FILTERED]", "remember_me"=>"0"}}
Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 125ms (ActiveRecord: 7.8ms)
==> gitlab-rails/production_json.log <==
{"method":"POST","path":"/users/sign_in","format":"html","controller":"SessionsController",
"action":"create","status":422,"error":"
ActionController::InvalidAuthenticityToken:ActionController::InvalidAuthenticityToken",
"duration":126.29,"view":0.0,"db":7.78,"time":"2017-12-23T00:22:16.039Z",
"params":{"authenticity_token":"[FILTERED]","user":{"login":"root","password":"
[FILTERED]","remember_me":"0"}},"remote_ip":"172.17.0.1",
"user_id":1,"username":"root"}
==> gitlab-rails/production.log <==
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
lib/gitlab/middleware/multipart.rb:93:in `call'
lib/gitlab/request_profiler/middleware.rb:14:in `call'
lib/gitlab/middleware/go.rb:18:in `call'
lib/gitlab/etag_caching/middleware.rb:11:in `call'
lib/gitlab/middleware/read_only.rb:31:in `call'
lib/gitlab/request_context.rb:18:in `call'
lib/gitlab/metrics/requests_rack_middleware.rb:27:in `call'
<?php
declare(strict_types = 1);
require_once ('hhb_.inc.php');
$hc = new hhb_curl ( '', true );
$html = $hc->exec ( 'https://gitlab.com/users/sign_in' )->getStdOut ();
$domd = @DOMDocument::loadHTML ( $html );
$inputs = getDOMDocumentFormInputs ( $domd, true, false ) ['new_user'];
// var_dump ( $inputs );
$inputs ['user[login]'] = '???';
$inputs ['user[password]'] = '???';
$html = $hc->setopt_array ( array (
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => http_build_query ( $inputs )
) )->exec ()->getStdOut ();
echo $html;
$domd = @DOMDocument::loadHTML ( $html );
$xp = new DOMXPath ( $domd );
foreach ( $xp->query ( '//div[contains(@class,"flash-alert")]' ) as $loginError ) {
var_dump ( "login error: ", trim($loginError->textContent) );
}
function getDOMDocumentFormInputs(\DOMDocument $domd, bool $getOnlyFirstMatches = false, bool $getElements = true): array {
// :DOMNodeList?
if (! $getOnlyFirstMatches && ! $getElements) {
throw new \InvalidArgumentException ( '!$getElements is currently only implemented for $getOnlyFirstMatches (cus im lazy and nobody has written the code yet)' );
}
$forms = $domd->getElementsByTagName ( 'form' );
$parsedForms = array ();
$isDescendantOf = function (\DOMNode $decendant, \DOMNode $ele): bool {
$parent = $decendant;
while ( NULL !== ($parent = $parent->parentNode) ) {
if ($parent === $ele) {
return true;
}
}
return false;
};
// i can't use array_merge on DOMNodeLists :(
$merged = function () use (&$domd): array {
$ret = array ();
foreach ( $domd->getElementsByTagName ( "input" ) as $input ) {
$ret [] = $input;
}
foreach ( $domd->getElementsByTagName ( "textarea" ) as $textarea ) {
$ret [] = $textarea;
}
foreach ( $domd->getElementsByTagName ( "button" ) as $button ) {
$ret [] = $button;
}
return $ret;
};
$merged = $merged ();
foreach ( $forms as $form ) {
$inputs = function () use (&$domd, &$form, &$isDescendantOf, &$merged): array {
$ret = array ();
foreach ( $merged as $input ) {
// hhb_var_dump ( $input->getAttribute ( "name" ), $input->getAttribute ( "id" ) );
if ($input->hasAttribute ( "disabled" )) {
// ignore disabled elements?
continue;
}
$name = $input->getAttribute ( "name" );
if ($name === '') {
// echo "inputs with no name are ignored when submitted by mainstream browsers (presumably because of specs)... follow suite?", PHP_EOL;
continue;
}
if (! $isDescendantOf ( $input, $form ) && $form->getAttribute ( "id" ) !== '' && $input->getAttribute ( "form" ) !== $form->getAttribute ( "id" )) {
// echo "this input does not belong to this form.", PHP_EOL;
continue;
}
if (! array_key_exists ( $name, $ret )) {
$ret [$name] = array (
$input
);
} else {
$ret [$name] [] = $input;
}
}
return $ret;
};
$inputs = $inputs (); // sorry about that, Eclipse gets unstable on IIFE syntax.
$hasName = true;
$name = $form->getAttribute ( "id" );
if ($name === '') {
$name = $form->getAttribute ( "name" );
if ($name === '') {
$hasName = false;
}
}
if (! $hasName) {
$parsedForms [] = array (
$inputs
);
} else {
if (! array_key_exists ( $name, $parsedForms )) {
$parsedForms [$name] = array (
$inputs
);
} else {
$parsedForms [$name] [] = $tmp;
}
}
}
unset ( $form, $tmp, $hasName, $name, $i, $input );
if ($getOnlyFirstMatches) {
foreach ( $parsedForms as $key => $val ) {
$parsedForms [$key] = $val [0];
}
unset ( $key, $val );
foreach ( $parsedForms as $key1 => $val1 ) {
foreach ( $val1 as $key2 => $val2 ) {
$parsedForms [$key1] [$key2] = $val2 [0];
}
}
}
if ($getElements) {
return $parsedForms;
}
$ret = array ();
foreach ( $parsedForms as $formName => $arr ) {
$ret [$formName] = array ();
foreach ( $arr as $ele ) {
$ret [$formName] [$ele->getAttribute ( "name" )] = $ele->getAttribute ( "value" );
}
}
return $ret;
}