backend: fixes backends import and sql backend
Migrate from sqlalchemy-migrate to alembic * mandaye/auth/authform.py: fix backend sql call * mandaye/backends/sql.py: fixes * mandaye/backends/default.py: fix backend call * mandaye/config.py: new backend call
This commit is contained in:
parent
b8708efc97
commit
e6211639e3
|
@ -0,0 +1,51 @@
|
|||
# A generic, single database configuration.
|
||||
|
||||
[alembic]
|
||||
# path to migration scripts
|
||||
script_location = alembic
|
||||
|
||||
# template used to generate migration files
|
||||
# file_template = %%(rev)s_%%(slug)s
|
||||
|
||||
# set to 'true' to run the environment during
|
||||
# the 'revision' command, regardless of autogenerate
|
||||
revision_environment = true
|
||||
|
||||
# Automatically set from mandaye config
|
||||
sqlalchemy.url = driver://user:pass@localhost/dbname
|
||||
|
||||
|
||||
# Logging configuration
|
||||
[loggers]
|
||||
keys = root,sqlalchemy,alembic
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = WARN
|
||||
handlers = console
|
||||
qualname =
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
|
||||
[logger_alembic]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = alembic
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(levelname)-5.5s [%(name)s] %(message)s
|
||||
datefmt = %H:%M:%S
|
|
@ -0,0 +1 @@
|
|||
Generic single-database configuration.
|
|
@ -0,0 +1,74 @@
|
|||
from __future__ import with_statement
|
||||
from alembic import context
|
||||
from sqlalchemy import engine_from_config, pool
|
||||
from logging.config import fileConfig
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
config = context.config
|
||||
|
||||
# Interpret the config file for Python logging.
|
||||
# This line sets up loggers basically.
|
||||
fileConfig(config.config_file_name)
|
||||
|
||||
# add your model's MetaData object here
|
||||
# for 'autogenerate' support
|
||||
from mandaye.models import Base
|
||||
target_metadata = Base.metadata
|
||||
|
||||
# Import db url form mandaye
|
||||
from mandaye.config import db_url
|
||||
config.set_main_option("sqlalchemy.url", db_url)
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
# my_important_option = config.get_main_option("my_important_option")
|
||||
# ... etc.
|
||||
|
||||
def run_migrations_offline():
|
||||
"""Run migrations in 'offline' mode.
|
||||
|
||||
This configures the context with just a URL
|
||||
and not an Engine, though an Engine is acceptable
|
||||
here as well. By skipping the Engine creation
|
||||
we don't even need a DBAPI to be available.
|
||||
|
||||
Calls to context.execute() here emit the given string to the
|
||||
script output.
|
||||
|
||||
"""
|
||||
url = config.get_main_option("sqlalchemy.url")
|
||||
context.configure(url=url)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
def run_migrations_online():
|
||||
"""Run migrations in 'online' mode.
|
||||
|
||||
In this scenario we need to create an Engine
|
||||
and associate a connection with the context.
|
||||
|
||||
"""
|
||||
engine = engine_from_config(
|
||||
config.get_section(config.config_ini_section),
|
||||
prefix='sqlalchemy.',
|
||||
poolclass=pool.NullPool)
|
||||
|
||||
connection = engine.connect()
|
||||
context.configure(
|
||||
connection=connection,
|
||||
target_metadata=target_metadata
|
||||
)
|
||||
|
||||
try:
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
if context.is_offline_mode():
|
||||
run_migrations_offline()
|
||||
else:
|
||||
run_migrations_online()
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
"""${message}
|
||||
|
||||
Revision ID: ${up_revision}
|
||||
Revises: ${down_revision}
|
||||
Create Date: ${create_date}
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = ${repr(up_revision)}
|
||||
down_revision = ${repr(down_revision)}
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
${imports if imports else ""}
|
||||
|
||||
def upgrade():
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
|
||||
def downgrade():
|
||||
${downgrades if downgrades else "pass"}
|
|
@ -0,0 +1,52 @@
|
|||
"""Initial tables
|
||||
|
||||
Revision ID: 913dfa11ef
|
||||
Revises: None
|
||||
Create Date: 2013-05-22 11:31:22.676232
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '913dfa11ef'
|
||||
down_revision = None
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
from mandaye.models import JSONEncodedDict
|
||||
|
||||
def upgrade():
|
||||
### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('idp_user',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('unique_id', sa.String(length=150), nullable=False),
|
||||
sa.Column('idp_id', sa.String(length=150), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('service_provider',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=50), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('name')
|
||||
)
|
||||
op.create_table('sp_user',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('login', sa.String(length=150), nullable=False),
|
||||
sa.Column('post_values', JSONEncodedDict(), nullable=False),
|
||||
sa.Column('creation_date', sa.DateTime(), nullable=False),
|
||||
sa.Column('last_connection', sa.DateTime(), nullable=True),
|
||||
sa.Column('idp_user_id', sa.Integer(), nullable=True),
|
||||
sa.Column('service_provider_id', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['idp_user_id'], ['idp_user.id'], ),
|
||||
sa.ForeignKeyConstraint(['service_provider_id'], ['service_provider.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('sp_user')
|
||||
op.drop_table('service_provider')
|
||||
op.drop_table('idp_user')
|
||||
### end Alembic commands ###
|
|
@ -23,7 +23,7 @@ from mandaye.response import _500, _302, _401
|
|||
from mandaye.response import template_response
|
||||
from mandaye.server import get_response
|
||||
|
||||
from mandaye.config import backend
|
||||
from mandaye.backends.default import backend
|
||||
|
||||
try:
|
||||
from Crypto.Cipher import AES
|
||||
|
@ -188,6 +188,7 @@ a password_field key if you want to encode a password.")
|
|||
unique_id: idp uinique id
|
||||
post_values: dict with the post values
|
||||
"""
|
||||
logger.debug('AuthForm._save_association', 'Save a new association')
|
||||
sp_login = post_values[self.form_values['username_field']]
|
||||
if config.encrypt_sp_password:
|
||||
self._encrypt_pwd(post_values)
|
||||
|
@ -275,8 +276,8 @@ a password_field key if you want to encode a password.")
|
|||
|
||||
logger.debug('User %s successfully login' % env['beaker.session']['unique_id'])
|
||||
|
||||
idp_user = backend.ManagerIDPUser.get(unique_id)
|
||||
service_provider = backend.ManagerServiceProvider.get(self.site_name)
|
||||
idp_user = backend.ManagerIDPUser.get_or_create(unique_id)
|
||||
service_provider = backend.ManagerServiceProvider.get_or_create(self.site_name)
|
||||
sp_user = backend.ManagerSPUser.get_last_connected(idp_user, service_provider)
|
||||
if not sp_user:
|
||||
logger.debug('User %s is not associate' % env['beaker.session']['unique_id'])
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
|
||||
from importlib import import_module
|
||||
|
||||
from mandaye.config import storage_backend
|
||||
from mandaye.exceptions import ImproperlyConfigured
|
||||
|
||||
class DefaultManagerIDPUser:
|
||||
|
||||
@staticmethod
|
||||
|
@ -73,4 +78,15 @@ class DefaultServiceProvider:
|
|||
def save(service_provider):
|
||||
pass
|
||||
|
||||
def import_backend(path):
|
||||
try:
|
||||
mod = import_module(path)
|
||||
except ImportError, e:
|
||||
raise ImproperlyConfigured('Error importing backend %s: "%s"' % (path, e))
|
||||
return mod
|
||||
|
||||
backend = import_backend(storage_backend)
|
||||
ManagerServiceProvider = backend.ManagerServiceProvider
|
||||
ManagerIDPUser = backend.ManagerIDPUser
|
||||
ManagerSPUser = backend.ManagerSPUser
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
from datetime import datetime
|
||||
|
||||
from mandaye.db import sql_session
|
||||
from mandaye.log import logger
|
||||
from mandaye.models import IDPUser, SPUser, ServiceProvider
|
||||
|
||||
class ManagerIDPUserSQL:
|
||||
|
@ -10,18 +11,19 @@ class ManagerIDPUserSQL:
|
|||
def get(unique_id, idp_id='default'):
|
||||
idp_user = sql_session().query(IDPUser).\
|
||||
filter_by(unique_id=unique_id,
|
||||
idp_id='default')
|
||||
idp_id='default').all()
|
||||
if len(idp_user) > 1:
|
||||
logger.critical('ManagerIDPUserSQL.get %s not unique' % unique_id)
|
||||
raise MandayeException(
|
||||
'ManagerIDPUserSQL.get : %s is not unique' % unique_id)
|
||||
if idp_user:
|
||||
return idp_user.first()
|
||||
return idp_user[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def create(unique_id, idp_id='default'):
|
||||
logger.info('Add idp user %s in db' % (unique_id))
|
||||
idp_user = IDPUser(
|
||||
unique_id=unique_id,
|
||||
idp_id=idp_id)
|
||||
|
@ -30,13 +32,15 @@ class ManagerIDPUserSQL:
|
|||
|
||||
@staticmethod
|
||||
def get_or_create(unique_id, idp_id='default'):
|
||||
if ManagerIDPUserSQL.get(**kwargs):
|
||||
return user
|
||||
idp_user= ManagerIDPUserSQL.get(unique_id, idp_id)
|
||||
if idp_user:
|
||||
return idp_user
|
||||
else:
|
||||
return ManagerIDPUserSQL.create(**kwargs)
|
||||
return ManagerIDPUserSQL.create(unique_id, idp_id)
|
||||
|
||||
@staticmethod
|
||||
def delete(idp_user):
|
||||
logger.info('Delete in db idp user %s' % idp_user.unique_id)
|
||||
sql_session().delete(idp_user)
|
||||
sql_session().commit()
|
||||
|
||||
|
@ -48,7 +52,7 @@ class ManagerSPUserSQL:
|
|||
|
||||
@staticmethod
|
||||
def get(login, idp_user, service_provider):
|
||||
sp_user = sql_session().query(SPPUser).\
|
||||
sp_user = sql_session().query(SPUser).\
|
||||
join(IDPUser).\
|
||||
join(ServiceProvider).\
|
||||
filter_by(login=login,
|
||||
|
@ -66,11 +70,10 @@ class ManagerSPUserSQL:
|
|||
|
||||
@staticmethod
|
||||
def get_last_connected(idp_user, service_provider):
|
||||
return sql_session().query(SPPUser).\
|
||||
join(IDPUser).\
|
||||
join(ServiceProvider).\
|
||||
filter(idp_user=idp_user).\
|
||||
filer(service_provider=service_provider).\
|
||||
print idp_user
|
||||
return sql_session().query(SPUser).\
|
||||
filter(SPUser.idp_user==idp_user).\
|
||||
filter(SPUser.service_provider==service_provider).\
|
||||
order_by(SPUser.last_connection.desc()).\
|
||||
first()
|
||||
@staticmethod
|
||||
|
@ -95,6 +98,7 @@ class ManagerSPUserSQL:
|
|||
(login, idp_user.unique_id, service_provider.name))
|
||||
sql_session().add(sp_user)
|
||||
sql_session().commit()
|
||||
logger.debug('New SP user %s in db' % (login))
|
||||
return idp_user
|
||||
|
||||
@staticmethod
|
||||
|
@ -132,7 +136,7 @@ class ManagerServiceProviderSQL:
|
|||
|
||||
@staticmethod
|
||||
def create(name):
|
||||
logger.info('Add %s service provider into the database' % name)
|
||||
logger.info('Add %s service provider into the db' % name)
|
||||
sp = ServiceProvider(name=name)
|
||||
sql_session().add(sp)
|
||||
sql_session().commit()
|
||||
|
@ -157,6 +161,6 @@ class ManagerServiceProviderSQL:
|
|||
sql_session().commit()
|
||||
|
||||
ManagerServiceProvider = ManagerServiceProviderSQL
|
||||
ManagerIDPUser = ManagerIDPUserSQL
|
||||
ManagerSPUser = ManagerSPUserSQL
|
||||
ManagerServiceProvider = ManagerServiceProviderSQL
|
||||
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import logging
|
||||
from mandaye.exceptions import ImproperlyConfigured
|
||||
|
||||
|
||||
# Choose storage
|
||||
# Only mandaye.backends.sql at the moment
|
||||
storage_backend = "mandaye.backends.sql"
|
||||
|
||||
## SQL Backend config
|
||||
# Database configuration
|
||||
# rfc 1738 http://rfc.net/rfc1738.html
|
||||
db_url = 'sqlite:///test.db'
|
||||
|
||||
# Default backend
|
||||
import mandaye.backends.sql
|
||||
backend = mandaye.backends.sql
|
||||
|
||||
# Needed if ssl is activated
|
||||
ssl = False
|
||||
keyfile = ''
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
This is a database migration repository.
|
||||
|
||||
More information at
|
||||
http://code.google.com/p/sqlalchemy-migrate/
|
|
@ -1 +0,0 @@
|
|||
# template repository default module
|
|
@ -1,5 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from migrate.versioning.shell import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(debug='False')
|
|
@ -1,25 +0,0 @@
|
|||
[db_settings]
|
||||
# Used to identify which repository this database is versioned under.
|
||||
# You can use the name of your project.
|
||||
repository_id=Mandaye migrations
|
||||
|
||||
# The name of the database table used to track the schema version.
|
||||
# This name shouldn't already be used by your project.
|
||||
# If this is changed once a database is under version control, you'll need to
|
||||
# change the table name in each database too.
|
||||
version_table=migrate_version
|
||||
|
||||
# When committing a change script, Migrate will attempt to generate the
|
||||
# sql for all supported databases; normally, if one of them fails - probably
|
||||
# because you don't have that database installed - it is ignored and the
|
||||
# commit continues, perhaps ending successfully.
|
||||
# Databases in this list MUST compile successfully during a commit, or the
|
||||
# entire commit will fail. List the databases your application will actually
|
||||
# be using to ensure your updates to that database work properly.
|
||||
# This must be a list; example: ['postgres','sqlite']
|
||||
required_dbs=[]
|
||||
|
||||
# When creating new change scripts, Migrate will stamp the new script with
|
||||
# a version number. By default this is latest_version + 1. You can set this
|
||||
# to 'true' to tell Migrate to use the UTC timestamp instead.
|
||||
use_timestamp_numbering=False
|
|
@ -1,118 +0,0 @@
|
|||
import collections
|
||||
import json
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Column, Integer, String, DateTime
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.ext.mutable import Mutable
|
||||
from sqlalchemy.orm import column_property, relationship, backref
|
||||
from sqlalchemy.types import TypeDecorator, VARCHAR
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
class JSONEncodedDict(TypeDecorator):
|
||||
"Represents an immutable structure as a json-encoded string."
|
||||
|
||||
impl = VARCHAR
|
||||
|
||||
def process_bind_param(self, value, dialect):
|
||||
if value is not None:
|
||||
value = json.dumps(value)
|
||||
return value
|
||||
|
||||
def process_result_value(self, value, dialect):
|
||||
if value is not None:
|
||||
value = json.loads(value)
|
||||
return value
|
||||
|
||||
class MutationDict(Mutable, dict):
|
||||
|
||||
@classmethod
|
||||
def coerce(cls, key, value):
|
||||
""" Convert plain dictionaries to MutationDict. """
|
||||
if not isinstance(value, MutationDict):
|
||||
if isinstance(value, dict):
|
||||
return MutationDict(value)
|
||||
# this call will raise ValueError
|
||||
return Mutable.coerce(key, value)
|
||||
else:
|
||||
return value
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
""" Detect dictionary set events and emit change events. """
|
||||
dict.__setitem__(self, key, value)
|
||||
self.changed()
|
||||
|
||||
def __delitem__(self, key):
|
||||
""" Detect dictionary del events and emit change events. """
|
||||
dict.__delitem__(self, key)
|
||||
self.changed()
|
||||
|
||||
MutationDict.associate_with(JSONEncodedDict)
|
||||
|
||||
class ServiceProvider(Base):
|
||||
|
||||
__tablename__ = 'service_provider'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String(50), unique=True, nullable=False)
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __repr__(self):
|
||||
return "<ServiceProvider('%s')>" % (self.name)
|
||||
|
||||
class IDPUser(Base):
|
||||
|
||||
__tablename__ = 'idp_user'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
# Nameid, pseudo, email, ...
|
||||
unique_id = Column(String(150), nullable=False)
|
||||
# Entityid
|
||||
idp_id = Column(String(150), nullable=False)
|
||||
sp_users = relationship("SPUser", backref=backref('idp_user'))
|
||||
|
||||
def __init__(self, unique_id=None, idp_id=None, sp_users=None):
|
||||
self.unique_id = unique_id
|
||||
self.idp_id = idp_id
|
||||
self.sp_users = sp_users
|
||||
|
||||
def __repr__(self):
|
||||
return "<IDPUser %d '%s'>" % (self.id, self.unique_id)
|
||||
|
||||
|
||||
class SPUser(Base):
|
||||
|
||||
__tablename__ = 'sp_user'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
post_values = Column(JSONEncodedDict, nullable=False)
|
||||
creation_date = Column(DateTime, default=datetime.now(), nullable=False)
|
||||
last_connection = Column(DateTime, default=datetime.now())
|
||||
|
||||
idp_user_id = Column(Integer, ForeignKey('idp_user.id'))
|
||||
service_provider_id = Column(Integer, ForeignKey('service_provider.id'),
|
||||
nullable=False)
|
||||
service_provider = relationship("ServiceProvider", backref=backref('users'))
|
||||
|
||||
def __init__(self, post_values=None):
|
||||
self.post_values = post_values
|
||||
|
||||
def __repr__(self):
|
||||
return "<SPUser '%d'>" % (self.id)
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
ServiceProvider.__table__.create(migrate_engine)
|
||||
SPUser.__table__.create(migrate_engine)
|
||||
IDPUser.__table__.create(migrate_engine)
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
ServiceProvider.__table__.drop(migrate_engine)
|
||||
SPUser.__table__.drop(migrate_engine)
|
||||
IDPUser.__table__.drop(migrate_engine)
|
||||
|
|
@ -1 +0,0 @@
|
|||
# template repository default versions module
|
|
@ -78,10 +78,9 @@ class IDPUser(Base):
|
|||
idp_id = Column(String(150), nullable=False)
|
||||
sp_users = relationship("SPUser", backref=backref('idp_user'))
|
||||
|
||||
def __init__(self, unique_id=None, idp_id=None, sp_users=None):
|
||||
def __init__(self, unique_id=None, idp_id=None):
|
||||
self.unique_id = unique_id
|
||||
self.idp_id = idp_id
|
||||
self.sp_users = sp_users
|
||||
|
||||
def __repr__(self):
|
||||
return "<IDPUser %d '%s'>" % (self.id, self.unique_id)
|
||||
|
|
|
@ -4,6 +4,6 @@ pycrypto>=2.0
|
|||
lxml>=2.0
|
||||
xtraceback>=0.3
|
||||
sqlalchemy>=0.7,<0.8
|
||||
sqlalchemy-migrate>=0.7
|
||||
alembic >= 0.5.0
|
||||
Mako>=0.4
|
||||
static
|
||||
|
|
|
@ -57,12 +57,10 @@ def main():
|
|||
if options.createdb:
|
||||
logger.info("Creating database...")
|
||||
if config.db_url:
|
||||
import migrate.versioning.api
|
||||
import mandaye.migration
|
||||
migrate.versioning.api.version_control(url=config.db_url,
|
||||
repository=mandaye.migration.__path__[0])
|
||||
migrate.versioning.api.upgrade(url=config.db_url,
|
||||
repository=mandaye.migration.__path__[0])
|
||||
from alembic.config import Config
|
||||
from alembic import command
|
||||
alembic_cfg = Config("alembic.ini")
|
||||
command.upgrade(alembic_cfg, "head")
|
||||
logger.info("Database created")
|
||||
if options.cryptpwd:
|
||||
from mandaye.config.backend import ManagerSPUser
|
||||
|
|
Reference in New Issue