Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
slapos.toolbox
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Alain Takoudjou
slapos.toolbox
Commits
325666f9
Commit
325666f9
authored
Mar 28, 2017
by
Alain Takoudjou
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
certificate_authority: reimplement with new api
parent
3cdc9427
Changes
11
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
587 additions
and
295 deletions
+587
-295
slapos/certificate_authority/certificate_authority.py
slapos/certificate_authority/certificate_authority.py
+88
-41
slapos/certificate_authority/request.py
slapos/certificate_authority/request.py
+7
-4
slapos/certificate_authority/run.py
slapos/certificate_authority/run.py
+16
-4
slapos/certificate_authority/web/models.py
slapos/certificate_authority/web/models.py
+1
-16
slapos/certificate_authority/web/settings.py
slapos/certificate_authority/web/settings.py
+45
-32
slapos/certificate_authority/web/start_web.py
slapos/certificate_authority/web/start_web.py
+8
-1
slapos/certificate_authority/web/tools/certificate.py
slapos/certificate_authority/web/tools/certificate.py
+18
-41
slapos/certificate_authority/web/tools/error.py
slapos/certificate_authority/web/tools/error.py
+55
-0
slapos/certificate_authority/web/tools/tools.py
slapos/certificate_authority/web/tools/tools.py
+9
-0
slapos/certificate_authority/web/tools/users.py
slapos/certificate_authority/web/tools/users.py
+33
-0
slapos/certificate_authority/web/views.py
slapos/certificate_authority/web/views.py
+307
-156
No files found.
slapos/certificate_authority/certificate_authority.py
View file @
325666f9
...
...
@@ -198,6 +198,19 @@ class CertificateBase(object):
else
:
return
False
def
checkCertificateValidity
(
self
,
ca_cert_file
,
cert_file
,
key_file
=
None
):
with
open
(
ca_cert_file
)
as
f_ca
:
ca_cert
=
f_ca
.
read
()
with
open
(
cert_file
)
as
f_cert
:
cert
=
f_cert
.
read
()
# XXX Considering only one trusted certificate here
if
not
self
.
verifyCertificateChain
(
cert
,
[
ca_cert
]):
return
False
if
key_file
:
return
self
.
validateCertAndKey
(
cert_file
,
key_file
)
return
True
def
generatePrivatekey
(
self
,
output_file
,
size
=
2048
):
key
=
crypto
.
PKey
()
key
.
generate_key
(
crypto
.
TYPE_RSA
,
size
)
...
...
@@ -215,7 +228,7 @@ class CertificateBase(object):
def
generateCertificateRequest
(
self
,
key_file
,
output_file
,
cn
,
country
,
state
,
locality
=
''
,
email
=
''
,
organization
=
''
,
organization_unit
=
''
,
digest
=
"sha
1
"
):
organization_unit
=
''
,
digest
=
"sha
256
"
):
with
open
(
key_file
)
as
fkey
:
key
=
crypto
.
load_privatekey
(
crypto
.
FILETYPE_PEM
,
fkey
.
read
())
...
...
@@ -238,20 +251,38 @@ class CertificateBase(object):
os
.
chmod
(
output_file
,
0644
)
def
checkCertificateValidity
(
self
,
ca_cert_file
,
cert_file
,
key_file
=
None
):
with
open
(
ca_cert_file
)
as
f_ca
:
ca_cert
=
f_ca
.
read
()
with
open
(
cert_file
)
as
f_cert
:
cert
=
f_cert
.
read
()
def
signData
(
self
,
key_file
,
data
,
digest
=
"sha256"
,
output_file
=
None
):
"""
Sign a data using digest and return signature. If output_file is provided
the signature will be written into the file.
"""
with
open
(
key_file
)
as
fkey
:
pkey
=
crypto
.
load_privatekey
(
crypto
.
FILETYPE_PEM
,
fkey
.
read
())
sign
=
crypto
.
sign
(
pkey
,
data
,
digest
)
# data_base64 = base64.b64encode(sign)
if
output_file
is
None
:
return
sign
fd
=
os
.
open
(
output_file
,
os
.
O_CREAT
|
os
.
O_WRONLY
|
os
.
O_EXCL
|
os
.
O_TRUNC
,
0644
)
try
:
os
.
write
(
fd
,
sign
)
finally
:
os
.
close
(
fd
)
return
sign
# XXX Considering only one trusted certificate here
if
not
self
.
verifyCertificateChain
(
cert
,
[
ca_cert
]):
return
False
return
False
if
key_file
:
return
self
.
validateCertAndKey
(
cert_file
,
key_file
)
return
True
def
verifyData
(
self
,
cert_string
,
signature
,
data
,
digest
=
"sha256"
):
"""
Verify the signature for a data string.
cert_string: is the certificate content as string
signature: is generate using 'signData' from the data to verify
data: content to verify
digest: by default is sha256, set the correct value
"""
x509
=
crypto
.
load_certificate
(
crypto
.
FILETYPE_PEM
,
cert
)
return
crypto
.
verify
(
x509
,
signature
,
data
,
digest
)
def
readCertificateRequest
(
self
,
csr
):
req
=
crypto
.
load_certificate_request
(
crypto
.
FILETYPE_PEM
,
csr
)
...
...
@@ -415,6 +446,11 @@ class CertificateAuthorityRequest(CertificateBase):
self
.
ca_url
=
ca_url
self
.
logger
=
logger
self
.
max_retry
=
max_retry
self
.
X509Extension
=
X509Extension
()
while
self
.
ca_url
.
endswith
(
'/'
):
# remove all / at end or ca_url
self
.
ca_url
=
self
.
ca_url
[:
-
1
]
if
self
.
logger
is
None
:
self
.
logger
=
logging
.
getLogger
(
'Certificate Request'
)
...
...
@@ -446,7 +482,7 @@ class CertificateAuthorityRequest(CertificateBase):
if
os
.
path
.
exists
(
self
.
cacertificate
)
and
os
.
stat
(
self
.
cacertificate
).
st_size
>
0
:
return
ca_cert_url
=
'%s/
ge
t/cacert.pem'
%
self
.
ca_url
ca_cert_url
=
'%s/
cr
t/cacert.pem'
%
self
.
ca_url
self
.
logger
.
info
(
"getting CA certificate file %s"
%
ca_cert_url
)
response
=
None
while
not
response
or
response
.
status_code
!=
200
:
...
...
@@ -479,7 +515,7 @@ class CertificateAuthorityRequest(CertificateBase):
data
=
{
'csr'
:
csr
}
retry
=
0
sleep_time
=
10
request_url
=
'%s/
request
'
%
self
.
ca_url
request_url
=
'%s/
csr
'
%
self
.
ca_url
# Save Cert in tmp to check later
cert_temp
=
'%s.tmp'
%
self
.
certificate
csr_key_file
=
'%s.key'
%
csr_file
...
...
@@ -491,31 +527,34 @@ class CertificateAuthorityRequest(CertificateBase):
csr_key
=
fkey
.
read
()
if
csr_key
:
self
.
logger
.
info
(
"Csr was already sent to CA,
key is
: %s"
%
csr_key
)
self
.
logger
.
info
(
"Csr was already sent to CA,
using csr
: %s"
%
csr_key
)
else
:
response
=
self
.
_request
(
'p
os
t'
,
request_url
,
data
=
data
)
response
=
self
.
_request
(
'p
u
t'
,
request_url
,
data
=
data
)
while
(
not
response
or
response
.
status_code
!=
20
0
)
and
retry
<
self
.
max_retry
:
while
(
not
response
or
response
.
status_code
!=
20
1
)
and
retry
<
self
.
max_retry
:
self
.
logger
.
error
(
"%s: Failed to sen
d
CSR.
\
n
%s"
%
(
self
.
logger
.
error
(
"%s: Failed to sen
t
CSR.
\
n
%s"
%
(
response
.
status_code
,
response
.
text
))
self
.
logger
.
info
(
"will retry in %s seconds..."
%
sleep_time
)
time
.
sleep
(
sleep_time
)
retry
+=
1
response
=
self
.
_request
(
'p
os
t'
,
request_url
,
data
=
data
)
response
=
self
.
_request
(
'p
u
t'
,
request_url
,
data
=
data
)
if
response
.
status_code
!=
20
0
:
raise
Exception
(
"ERROR: failed to p
os
t CSR after % retry. Exiting..."
%
retry
)
if
response
.
status_code
!=
20
1
:
raise
Exception
(
"ERROR: failed to p
u
t CSR after % retry. Exiting..."
%
retry
)
self
.
logger
.
info
(
"CSR succefully sent."
)
self
.
logger
.
debug
(
"Server reponse with csr key is %s"
%
response
.
text
)
csr_key
=
response
.
text
# Get csr Location from request header: http://xxx.com/csr/key
self
.
logger
.
debug
(
"Csr location is: %s"
%
response
.
headers
[
'Location'
])
csr_key
=
response
.
headers
[
'Location'
].
split
(
'/'
)[
-
1
]
with
open
(
csr_key_file
,
'w'
)
as
fkey
:
fkey
.
write
(
response
.
text
)
# csr is xxx.csr.pem so cert is xxx.cert.pem
self
.
logger
.
info
(
"Waiting for signed certificate..."
)
reply_url
=
'%s/
get/%s.cert.pem'
%
(
self
.
ca_url
,
csr_key
)
reply_url
=
'%s/
crt/%s.cert.pem'
%
(
self
.
ca_url
,
csr_key
[:
-
8
]
)
response
=
self
.
_request
(
'get'
,
reply_url
)
while
not
response
or
response
.
status_code
!=
200
:
...
...
@@ -535,7 +574,7 @@ class CertificateAuthorityRequest(CertificateBase):
os
.
close
(
fd
)
os
.
unlink
(
cert_temp
)
else
:
if
auto_revoke
:
"""
if auto_revoke:
self.logger.error("Certificate validation failed. "
\
"The signed certificate is going to be revoked...")
self.revokeCertificateRequest(cert_temp,
...
...
@@ -547,38 +586,46 @@ class CertificateAuthorityRequest(CertificateBase):
except OSError, e:
if e.errno != errno.ENOENT:
# raise
pass
pass
"""
raise
Exception
(
"Error: Certificate validation failed. "
\
"This signed certificate should be revoked!"
)
self
.
logger
.
info
(
"Certificate correctly saved at %s."
%
self
.
certificate
)
def
revokeCertificateRequest
(
self
,
cert_file
,
key_name
,
message
=
""
):
def
revokeCertificateRequest
(
self
,
cert_file
,
message
=
""
):
"""
Send a revocation request for the givent certificate to the master.
"""
sleep_time
=
10
retry
=
0
cert
=
self
.
freadX509
(
cert_file
)
serial
=
'{0:x}'
.
format
(
int
(
cert
.
get_serial_number
()))
request_url
=
'%s/requestrevoke'
%
self
.
ca_url
data
=
{
'serial'
:
serial
,
'name'
:
key_name
,
'reason'
:
message
}
self
.
logger
.
info
(
"Sent Certificate revocation request for %s, serial=%s."
%
(
key_name
,
serial
))
response
=
self
.
_request
(
'post'
,
request_url
,
data
=
data
)
with
open
(
cert_file
)
as
f
:
cert_string
=
f
.
read
()
cert
=
self
.
readX509
(
cert_string
)
digest
=
"sha256"
payload
=
json
.
dumps
(
dict
(
reason
=
message
,
cert
=
cert_string
))
signature
=
self
.
signData
(
self
.
key
,
payload
,
digest
)
request_url
=
'%s/crt/revoke'
%
self
.
ca_url
data
=
{
'digest'
:
digest
,
'payload'
:
payload
,
'signature'
:
signature
}
self
.
logger
.
info
(
"Sent Certificate revocation request for CN: %s."
%
(
cert
.
get_subject
().
CN
))
response
=
self
.
_request
(
'put'
,
request_url
,
data
=
data
)
while
(
not
response
or
response
.
status_code
!=
20
0
)
and
retry
<
self
.
max_retry
:
while
(
not
response
or
response
.
status_code
!=
20
1
)
and
retry
<
self
.
max_retry
:
self
.
logger
.
error
(
"%s: Failed to send Rovocation request.
\
n
%s"
%
(
response
.
status_code
,
response
.
text
))
self
.
logger
.
info
(
"will retry in %s seconds..."
%
sleep_time
)
time
.
sleep
(
sleep_time
)
retry
+=
1
response
=
self
.
_request
(
'p
os
t'
,
request_url
,
data
=
data
)
response
=
self
.
_request
(
'p
u
t'
,
request_url
,
data
=
data
)
if
response
.
status_code
!=
20
0
:
if
response
.
status_code
!=
20
1
:
raise
Exception
(
"ERROR: failed to post revoke request after %s retry. Exiting..."
%
retry
)
self
.
logger
.
info
(
"Certificate revocation request for %s
.cert.pem
successfully sent."
%
(
key_nam
e
))
self
.
logger
.
info
(
"Certificate revocation request for %s successfully sent."
%
(
cert_fil
e
))
slapos/certificate_authority/request.py
View file @
325666f9
...
...
@@ -50,9 +50,12 @@ def parseArguments():
parser
.
add_argument
(
'--organization_unit'
,
default
=
'Company Unit'
,
help
=
'The Organisation Unit Name'
)
parser
.
add_argument
(
'--auto_revoke'
,
default
=
True
,
action
=
"store_true"
,
help
=
'Request Revoke Certificate if validation fail'
)
parser
.
add_argument
(
'--revoke'
,
default
=
False
,
action
=
"store_true"
,
help
=
'Revoke the current certificate'
)
parser
.
add_argument
(
'--revoke_reason'
,
help
=
'Say why the certificat should be revoked'
)
return
parser
...
...
@@ -84,7 +87,7 @@ def requestCertificateWeb():
cn
=
config
.
cn
,
country
=
config
.
country
,
state
=
config
.
state
,
locality
=
config
.
locality
,
email
=
config
.
email
,
organization
=
config
.
organization
,
organization_unit
=
config
.
organization_unit
,
digest
=
"sha
1
"
)
organization_unit
=
config
.
organization_unit
,
digest
=
"sha
256
"
)
ca
.
signCertificateWeb
(
config
.
csr_file
,
auto_revoke
=
config
.
auto_revoke
)
slapos/certificate_authority/run.py
View file @
325666f9
...
...
@@ -13,7 +13,6 @@ import traceback
from
flask_user
import
UserManager
,
SQLAlchemyAdapter
from
flask_mail
import
Mail
from
slapos.certificate_authority.web.views
import
app
from
slapos.certificate_authority.web.start_web
import
app
,
db
,
init_app
from
slapos.certificate_authority.certificate_authority
import
CertificateAuthority
def
parseArguments
():
...
...
@@ -53,6 +52,9 @@ def parseArguments():
help
=
'Path for log output'
)
parser
.
add_argument
(
'--db_file'
,
help
=
'Path of file to use to store User Account information. Default: $ca_dir/ca.db'
)
#parser.add_argument('--external_url',
# default='',
# help='The HTTP URL used to connect to CA server')
parser
.
add_argument
(
'--trusted_host'
,
default
=
[],
action
=
'append'
,
dest
=
'trusted_host_list'
,
...
...
@@ -89,13 +91,16 @@ def start():
"""
start certificate authority service
"""
flask
.
config
.
Config
.
__getattr__
=
getConfig
options
=
parseArguments
()
if
not
options
.
ca_dir
:
options
.
ca_dir
=
os
.
getcwd
()
else
:
options
.
ca_dir
=
os
.
path
.
abspath
(
options
.
ca_dir
)
os
.
environ
[
'CA_INSTANCE_PATH'
]
=
options
.
ca_dir
from
slapos.certificate_authority.web.start_web
import
app
,
db
,
init_app
flask
.
config
.
Config
.
__getattr__
=
getConfig
if
not
options
.
config_file
:
options
.
config_file
=
os
.
path
.
join
(
options
.
ca_dir
,
'openssl.cnf'
)
if
not
options
.
db_file
:
...
...
@@ -116,11 +121,15 @@ def start():
os
.
chdir
(
options
.
ca_dir
)
logger
=
getLogger
(
options
.
debug
,
options
.
log_file
)
app
.
logger
.
addHandler
(
logger
)
ca
=
CertificateAuthority
(
options
.
openssl_bin
,
openssl_configuration
=
options
.
config_file
,
certificate
=
options
.
cert_file
,
key
=
options
.
key_file
,
crl
=
options
.
crl_file
,
ca_directory
=
options
.
ca_dir
)
app
.
config
.
from_object
(
'slapos.certificate_authority.web.settings'
)
if
options
.
debug
:
app
.
config
.
from_object
(
'slapos.certificate_authority.web.settings.Development'
)
else
:
app
.
config
.
from_object
(
'slapos.certificate_authority.web.settings.Production'
)
app
.
config
.
update
(
ca_dir
=
options
.
ca_dir
,
trusted_host_list
=
options
.
trusted_host_list
,
...
...
@@ -134,8 +143,12 @@ def start():
SQLALCHEMY_DATABASE_URI
=
'sqlite:///%s'
%
options
.
db_file
,
ca
=
ca
,
log_file
=
options
.
log_file
,
# base_url=(options.external_url or 'http://%s:%s' % (options.host, options.port))
)
if
os
.
path
.
exists
(
os
.
path
.
join
(
options
.
ca_dir
,
'local.setting.py'
)):
app
.
config
.
from_pyfile
(
'local.setting.py'
,
silent
=
True
)
for
key
in
[
'csr'
,
'req'
,
'cert'
,
'crl'
,
'key'
,
'newcert'
]:
try
:
path
=
app
.
config
[
'%s_dir'
%
key
]
...
...
@@ -154,7 +167,6 @@ def start():
# Initialize Flask extensions
init_app
()
app
.
logger
.
addHandler
(
logger
)
app
.
logger
.
info
(
"Certificate Authority server started on http://%s:%s"
%
(
options
.
host
,
options
.
port
))
app
.
run
(
...
...
slapos/certificate_authority/web/models.py
View file @
325666f9
...
...
@@ -49,22 +49,7 @@ class Certificate(db.Model):
def
__repr__
(
self
):
return
'<CertificateMap %r>'
%
(
self
.
serial
)
class
Revoke
(
db
.
Model
):
"""
This table contains information about certificate revocation
"""
__tablename__
=
'revoke'
id
=
db
.
Column
(
db
.
Integer
,
primary_key
=
True
)
comment
=
db
.
Column
(
db
.
Text
())
serial
=
db
.
Column
(
db
.
String
(
50
),
unique
=
True
)
revoke_date
=
db
.
Column
(
db
.
DateTime
)
# link to revoke request if was requested by users
revoke_request_id
=
db
.
Column
(
db
.
Integer
,
server_default
=
''
)
def
__repr__
(
self
):
return
'<CertificateMap %r>'
%
(
self
.
serial
)
class
RevokeRequest
(
db
.
Model
):
class
Revocation
(
db
.
Model
):
"""
This table store certificate revocation request from users
"""
...
...
slapos/certificate_authority/web/settings.py
View file @
325666f9
import
os
# Application settings
APP_NAME
=
"Certificate Authority web app"
# DO NOT use "DEBUG = True" in production environments
DEBUG
=
True
class
BaseConfig
(
object
):
# DO NOT use Unsecure Secrets in production environments
# Generate a safe one with:
# python -c "import os; print repr(os.urandom(24));"
SECRET_KEY
=
'This is an UNSECURE Secret. CHANGE THIS for production environments.'
# Application settings
APP_NAME
=
"Certificate Authority web app"
# DO NOT use Unsecure Secrets in production environments
# Generate a safe one with:
# python -c "import os; print repr(os.urandom(24));"
SECRET_KEY
=
'This is an UNSECURE Secret. CHANGE THIS for production environments.'
# SQLAlchemy settings
SQLALCHEMY_DATABASE_URI
=
'sqlite:///ca.db'
SQLALCHEMY_TRACK_MODIFICATIONS
=
False
CSRF_ENABLED
=
True
# Flask-Mail settings
# For smtp.gmail.com to work, you MUST set "Allow less secure apps" to ON in Google Accounts.
# Change it in https://myaccount.google.com/security#connectedapps (near the bottom).
MAIL_SERVER
=
'smtp.gmail.com'
MAIL_PORT
=
587
MAIL_USE_SSL
=
False
MAIL_USE_TLS
=
True
MAIL_USERNAME
=
'yourname@gmail.com'
MAIL_PASSWORD
=
'password'
MAIL_DEFAULT_SENDER
=
'"Your Name" <yourname@gmail.com>'
# Used by email templates
USER_APP_NAME
=
"Certificate Authority"
# Internal view application
USER_AFTER_LOGIN_ENDPOINT
=
''
USER_AFTER_LOGOUT_ENDPOINT
=
''
USER_ENABLE_USERNAME
=
True
USER_ENABLE_EMAIL
=
False
USER_ENABLE_REGISTRATION
=
False
USER_ENABLE_CHANGE_USERNAME
=
False
# Allowed digest for signature
CA_DIGEST_LIST
=
[
'sha256'
,
'sha384'
,
'sha512'
]
# SQLAlchemy settings
SQLALCHEMY_DATABASE_URI
=
'sqlite:///ca.db'
SQLALCHEMY_TRACK_MODIFICATIONS
=
False
CSRF_ENABLED
=
True
# Flask-Mail settings
# For smtp.gmail.com to work, you MUST set "Allow less secure apps" to ON in Google Accounts.
# Change it in https://myaccount.google.com/security#connectedapps (near the bottom).
MAIL_SERVER
=
'smtp.gmail.com'
MAIL_PORT
=
587
MAIL_USE_SSL
=
False
MAIL_USE_TLS
=
True
MAIL_USERNAME
=
'yourname@gmail.com'
MAIL_PASSWORD
=
'password'
MAIL_DEFAULT_SENDER
=
'"Your Name" <yourname@gmail.com>'
class
Development
(
BaseConfig
):
DEBUG
=
True
TESTING
=
True
# Used by email templates
USER_APP_NAME
=
"Certificate Authority"
# Internal application
USER_AFTER_LOGIN_ENDPOINT
=
''
USER_AFTER_LOGOUT_ENDPOINT
=
''
USER_ENABLE_USERNAME
=
True
USER_ENABLE_EMAIL
=
False
USER_ENABLE_REGISTRATION
=
False
USER_ENABLE_CHANGE_USERNAME
=
False
\ No newline at end of file
class
Production
(
BaseConfig
):
# DO NOT use "DEBUG = True" in production environments
DEBUG
=
False
TESTING
=
False
\ No newline at end of file
slapos/certificate_authority/web/start_web.py
View file @
325666f9
...
...
@@ -2,9 +2,16 @@ from flask_sqlalchemy import SQLAlchemy
from
flask_user
import
UserManager
,
SQLAlchemyAdapter
from
flask
import
Flask
from
flask_mail
import
Mail
from
slapos.certificate_authority.web.settings
import
BaseConfig
import
os
app
=
Flask
(
__name__
)
# CA_INSTANCE_PATH is the base directory of application, send to environ
app
=
Flask
(
__name__
,
instance_path
=
config_name
=
os
.
getenv
(
'CA_INSTANCE_PATH'
,
os
.
getcwd
()),
instance_relative_config
=
True
)
# Use default value so SQLALCHEMY will not warn because there is not db_uri
app
.
config
[
'SQLALCHEMY_DATABASE_URI'
]
=
BaseConfig
.
SQLALCHEMY_DATABASE_URI
db
=
SQLAlchemy
(
app
)
def
init_app
():
...
...
slapos/certificate_authority/web/tools.py
→
slapos/certificate_authority/web/tools
/certificate
.py
View file @
325666f9
...
...
@@ -5,45 +5,20 @@ import time
import
urllib
from
datetime
import
datetime
from
slapos.certificate_authority.web.start_web
import
app
,
db
from
slapos.certificate_authority.web.models
import
(
User
,
Certificate
,
from
slapos.certificate_authority.web.models
import
(
Certificate
,
RevokeRequest
,
Revoke
,
CERT_STATUS_VALIDATED
,
CERT_STATUS_REVOKED
,
CERT_STATUS_PENDING
,
CERT_STATUS_REJECTED
)
from
slapos.certificate_authority.certificate_authority
import
CertificateBase
def
find_or_create_user
(
first_name
,
last_name
,
email
,
username
,
password
):
""" Find existing user or create new user """
class
CertificateTools
:
user
=
User
.
query
.
filter
(
User
.
username
==
username
).
first
()
if
not
user
:
user
=
User
(
email
=
email
,
first_name
=
first_name
,
last_name
=
last_name
,
username
=
username
,
password
=
app
.
user_manager
.
hash_password
(
password
),
active
=
True
,
confirmed_at
=
datetime
.
utcnow
()
)
db
.
session
.
add
(
user
)
db
.
session
.
commit
()
return
user
def
find_user
(
username
):
return
User
.
query
.
filter
(
User
.
username
==
username
).
first
()
def
get_string_num
(
number
):
if
number
<
10
:
return
'0%s'
%
number
return
str
(
number
)
class
CertificateTools
(
object
):
def
signCertificate
(
self
,
cert_id
,
req_file
):
def
signCertificate
(
self
,
req_file
,
cert_id
):
"""
Sign a certificate, cert_id is the name used by the user to download the cert
"""
csr_dest
=
os
.
path
.
join
(
app
.
config
.
csr_dir
,
'%s.csr.pem'
%
cert_id
)
cert_name
=
'%s.cert.pem'
%
cert_id
try
:
# Avoid signing two certificate at the same time (for unique serial)
app
.
config
.
ca
.
_lock
()
...
...
@@ -58,7 +33,7 @@ class CertificateTools(object):
app
.
config
.
ca
.
signCertificateRequest
(
req_file
,
output
)
cert
=
app
.
config
.
ca
.
freadX509
(
output
)
cert_db
=
Certificate
(
name
=
'%s.cert.pem'
%
cert_id
,
name
=
cert_name
,
serial
=
next_serial
,
filename
=
'%s.cert.pem'
%
next_serial
,
common_name
=
cert
.
get_subject
().
CN
,
...
...
@@ -89,17 +64,17 @@ class CertificateTools(object):
finally
:
app
.
config
.
ca
.
_unlock
()
def
addRevokeRequest
(
self
,
serial
,
hash_name
,
message
):
cert_path
=
os
.
path
.
join
(
app
.
config
.
cert_dir
,
'%s.cert.pem'
%
serial
)
if
not
os
.
path
.
exists
(
cert_path
):
# This check is fast but 'serial'.cert.pem should the the cert filename in db
return
False
return
cert_name
def
addRevokeRequest
(
self
,
cert
,
message
):
x509
=
app
.
config
.
ca
.
readX509
(
cert
)
serial
=
self
.
getSerialToInt
(
x509
)
cert
=
Certificate
.
query
.
filter
(
Certificate
.
status
==
CERT_STATUS_VALIDATED
).
filter
(
Certificate
.
serial
==
serial
).
first
()
).
filter
(
Certificate
.
serial
==
get_string_num
(
serial
)
).
first
()
if
not
cert
or
cert
.
name
!=
'%s.cert.pem'
%
hash_name
:
# This certificate not found or not match
# This certificate not found or not match
or was revoked
return
False
# Create Request
...
...
@@ -161,8 +136,8 @@ class CertificateTools(object):
return
""
def
getCertificateList
(
self
,
with_cacerts
=
True
):
ca_cert
=
app
.
config
.
ca
.
freadX509
(
app
.
config
.
ca
.
certificate
)
if
with_cacerts
:
ca_cert
=
app
.
config
.
ca
.
freadX509
(
app
.
config
.
ca
.
certificate
)
data_list
=
[
{
'index'
:
1
,
...
...
@@ -170,6 +145,7 @@ class CertificateTools(object):
'name'
:
os
.
path
.
basename
(
app
.
config
.
ca
.
certificate
),
'cn'
:
ca_cert
.
get_subject
().
CN
,
'expiration_date'
:
datetime
.
strptime
(
ca_cert
.
get_notAfter
(),
"%Y%m%d%H%M%SZ"
),
'start_date'
:
datetime
.
strptime
(
ca_cert
.
get_notBefore
(),
"%Y%m%d%H%M%SZ"
)
},
{
'index'
:
2
,
...
...
@@ -177,6 +153,7 @@ class CertificateTools(object):
'name'
:
os
.
path
.
basename
(
app
.
config
.
ca
.
ca_crl
),
'cn'
:
"Certificate Revocation List"
,
'expiration_date'
:
'---'
,
'start_date'
:
'---'
,
}
]
index
=
3
...
...
@@ -197,7 +174,7 @@ class CertificateTools(object):
'start_date'
:
signed_cert
.
start_before
,
})
index
+=
1
return
data_list
def
getRevokedCertificateList
(
self
):
...
...
@@ -217,7 +194,7 @@ class CertificateTools(object):
'start_date'
:
revoked_cert
.
start_before
,
})
index
+=
1
return
data_list
def
getRevocationRequestList
(
self
):
...
...
slapos/certificate_authority/web/tools/error.py
0 → 100644
View file @
325666f9
import
os
class
Error
():
MISSING_PARAM
=
{
code
:
1
,
name
:
"MissingParameter"
,
message
:
"Parameter(s) required is missing or empty."
}
CSR_FORMAT
=
{
code
:
2
,
name
:
"FileFormat"
,
message
:
"Not a valid PEM certificate signing request"
}
CSR_INVALID_CN
=
{
code
:
3
,
name
:
"CertificateSigningRequestContent"
,
message
:
"Request does not contain a Common Name"
}
CERT_FORMAT
=
{
code
:
4
,
name
:
"FileFormat"
,
message
:
"Not a valid PEM certificate"
}
SIGNATURE_VERIFICATION
=
{
code
:
5
,
name
:
"SignatureMismatch"
,
message
:
"Signature verification failed. Request was not signed with the correct key"
}
BAD_SIGNATURE_DIGEST
=
{
code
:
6
,
name
:
"SignatureMismatch"
,
message
:
"Hash algorithm not supported"
}
CSR_CONTENT_MISMATCH
=
{
code
:
7
,
name
:
"CertificateSigningRequestContent"
,
message
:
"Request content does not match replaced certificate"
}
JSON_FORMAT
=
{
code
:
8
,
name
:
"JsonFormat"
,
message
:
"Not a valid Json content submitted"
}
PAYLOAD_CONTENT
=
{
code
:
9
,
name
:
"PayloadContentInvalid"
,
message
:
"Submitted payload parameter is not valid"
}
INVALID_DIGEST
=
{
code
:
4
,
name
:
"IvalidORNotAllowedDigest"
,
message
:
"The Digest submitted is not accepted by CA or is invalid"
}
slapos/certificate_authority/web/tools/tools.py
0 → 100644
View file @
325666f9
# -*- coding: utf-8 -*-
import
os
def
get_string_num
(
number
):
if
number
<
10
:
return
'0%s'
%
number
return
str
(
number
)
\ No newline at end of file
slapos/certificate_authority/web/tools/users.py
0 → 100644
View file @
325666f9
# -*- coding: utf-8 -*-
import
os
from
datetime
import
datetime
from
slapos.certificate_authority.web.start_web
import
app
,
db
from
slapos.certificate_authority.web.models
import
User
def
check_authentication
(
username
,
password
):
user
=
self
.
find_user
(
username
):
if
user
:
return
app
.
user_manager
.
hash_password
(
password
)
==
user
.
password
else
:
return
False
def
find_or_create_user
(
first_name
,
last_name
,
email
,
username
,
password
):
""" Find existing user or create new user """
user
=
User
.
query
.
filter
(
User
.
username
==
username
).
first
()
if
not
user
:
user
=
User
(
email
=
email
,
first_name
=
first_name
,
last_name
=
last_name
,
username
=
username
,
password
=
app
.
user_manager
.
hash_password
(
password
),
active
=
True
,
confirmed_at
=
datetime
.
utcnow
()
)
db
.
session
.
add
(
user
)
db
.
session
.
commit
()
return
user
def
find_user
(
username
):
return
User
.
query
.
filter
(
User
.
username
==
username
).
first
()
\ No newline at end of file
slapos/certificate_authority/web/views.py
View file @
325666f9
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment