Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/awscli/customizations/codecommit.py
1566 views
1
# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License"). You
4
# may not use this file except in compliance with the License. A copy of
5
# the License is located at
6
#
7
# http://aws.amazon.com/apache2.0/
8
#
9
# or in the "license" file accompanying this file. This file is
10
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
# ANY KIND, either express or implied. See the License for the specific
12
# language governing permissions and limitations under the License.
13
14
import os
15
import re
16
import sys
17
import logging
18
import fileinput
19
20
from botocore.auth import SigV4Auth
21
from botocore.awsrequest import AWSRequest
22
from botocore.compat import urlsplit
23
from awscli.customizations.commands import BasicCommand
24
from awscli.compat import NonTranslatedStdout, get_current_datetime
25
26
logger = logging.getLogger('botocore.credentials')
27
28
29
def initialize(cli):
30
"""
31
The entry point for the credential helper
32
"""
33
cli.register('building-command-table.codecommit', inject_commands)
34
35
36
def inject_commands(command_table, session, **kwargs):
37
"""
38
Injects new commands into the codecommit subcommand.
39
"""
40
command_table['credential-helper'] = CodeCommitCommand(session)
41
42
43
class CodeCommitNoOpStoreCommand(BasicCommand):
44
NAME = 'store'
45
DESCRIPTION = ('This operation does nothing, credentials'
46
' are calculated each time')
47
SYNOPSIS = ('aws codecommit credential-helper store')
48
EXAMPLES = ''
49
_UNDOCUMENTED = True
50
51
def _run_main(self, args, parsed_globals):
52
return 0
53
54
55
class CodeCommitNoOpEraseCommand(BasicCommand):
56
NAME = 'erase'
57
DESCRIPTION = ('This operation does nothing, no credentials'
58
' are ever stored')
59
SYNOPSIS = ('aws codecommit credential-helper erase')
60
EXAMPLES = ''
61
_UNDOCUMENTED = True
62
63
def _run_main(self, args, parsed_globals):
64
return 0
65
66
67
class CodeCommitGetCommand(BasicCommand):
68
NAME = 'get'
69
DESCRIPTION = ('get a username SigV4 credential pair'
70
' based on protocol, host and path provided'
71
' from standard in. This is primarily'
72
' called by git to generate credentials to'
73
' authenticate against AWS CodeCommit')
74
SYNOPSIS = ('aws codecommit credential-helper get')
75
EXAMPLES = (r'echo -e "protocol=https\\n'
76
r'path=/v1/repos/myrepo\\n'
77
'host=git-codecommit.us-east-1.amazonaws.com"'
78
' | aws codecommit credential-helper get')
79
ARG_TABLE = [
80
{
81
'name': 'ignore-host-check',
82
'action': 'store_true',
83
'default': False,
84
'group_name': 'ignore-host-check',
85
'help_text': (
86
'Optional. Generate credentials regardless of whether'
87
' the domain is an Amazon domain.'
88
)
89
}
90
]
91
92
def __init__(self, session):
93
super(CodeCommitGetCommand, self).__init__(session)
94
95
def _run_main(self, args, parsed_globals):
96
git_parameters = self.read_git_parameters()
97
if ('amazon.com' in git_parameters['host'] or
98
'amazonaws.com' in git_parameters['host'] or
99
args.ignore_host_check):
100
theUrl = self.extract_url(git_parameters)
101
region = self.extract_region(git_parameters, parsed_globals)
102
signature = self.sign_request(region, theUrl)
103
self.write_git_parameters(signature)
104
return 0
105
106
def write_git_parameters(self, signature):
107
username = self._session.get_credentials().access_key
108
if self._session.get_credentials().token is not None:
109
username += "%" + self._session.get_credentials().token
110
# Python will add a \r to the line ending for a text stdout in Windows.
111
# Git does not like the \r, so switch to binary
112
with NonTranslatedStdout() as binary_stdout:
113
binary_stdout.write('username={0}\n'.format(username))
114
logger.debug('username\n%s', username)
115
binary_stdout.write('password={0}\n'.format(signature))
116
# need to explicitly flush the buffer here,
117
# before we turn the stream back to text for windows
118
binary_stdout.flush()
119
logger.debug('signature\n%s', signature)
120
121
def read_git_parameters(self):
122
parsed = {}
123
for line in sys.stdin:
124
line = line.strip()
125
if line:
126
key, value = line.split('=', 1)
127
parsed[key] = value
128
return parsed
129
130
def extract_url(self, parameters):
131
url = '{0}://{1}/{2}'.format(parameters['protocol'],
132
parameters['host'],
133
parameters['path'])
134
return url
135
136
def extract_region(self, parameters, parsed_globals):
137
match = re.match(r'(vpce-.+\.)?git-codecommit(-fips)?\.([^.]+)\.(vpce\.)?amazonaws\.com',
138
parameters['host'])
139
if match is not None:
140
return match.group(3)
141
elif parsed_globals.region is not None:
142
return parsed_globals.region
143
else:
144
return self._session.get_config_variable('region')
145
146
def sign_request(self, region, url_to_sign):
147
credentials = self._session.get_credentials()
148
signer = SigV4Auth(credentials, 'codecommit', region)
149
request = AWSRequest()
150
request.url = url_to_sign
151
request.method = 'GIT'
152
now = get_current_datetime()
153
request.context['timestamp'] = now.strftime('%Y%m%dT%H%M%S')
154
split = urlsplit(request.url)
155
# we don't want to include the port number in the signature
156
hostname = split.netloc.split(':')[0]
157
canonical_request = '{0}\n{1}\n\nhost:{2}\n\nhost\n'.format(
158
request.method,
159
split.path,
160
hostname)
161
logger.debug("Calculating signature using v4 auth.")
162
logger.debug('CanonicalRequest:\n%s', canonical_request)
163
string_to_sign = signer.string_to_sign(request, canonical_request)
164
logger.debug('StringToSign:\n%s', string_to_sign)
165
signature = signer.signature(string_to_sign, request)
166
logger.debug('Signature:\n%s', signature)
167
return '{0}Z{1}'.format(request.context['timestamp'], signature)
168
169
170
class CodeCommitCommand(BasicCommand):
171
NAME = 'credential-helper'
172
SYNOPSIS = ('aws codecommit credential-helper')
173
EXAMPLES = ''
174
175
SUBCOMMANDS = [
176
{'name': 'get', 'command_class': CodeCommitGetCommand},
177
{'name': 'store', 'command_class': CodeCommitNoOpStoreCommand},
178
{'name': 'erase', 'command_class': CodeCommitNoOpEraseCommand},
179
]
180
DESCRIPTION = ('Provide a SigV4 compatible user name and'
181
' password for git smart HTTP '
182
' These commands are consumed by git and'
183
' should not used directly. Erase and Store'
184
' are no-ops. Get is operation to generate'
185
' credentials to authenticate AWS CodeCommit.'
186
' Run \"aws codecommit credential-helper help\"'
187
' for details')
188
189
def _run_main(self, args, parsed_globals):
190
raise ValueError('usage: aws [options] codecommit'
191
' credential-helper <subcommand> '
192
'[parameters]\naws: error: too few arguments')
193
194