コード例 #1
0
    def test_access_token_with_fetch_token(self):
        app = Flask(__name__)
        app.secret_key = '!'
        oauth = OAuth()

        token = get_bearer_token()
        oauth.init_app(app, fetch_token=lambda name: token)
        client = oauth.register('dev',
                                client_id='dev',
                                client_secret='dev',
                                api_base_url='https://i.b/api',
                                access_token_url='https://i.b/token',
                                authorize_url='https://i.b/authorize')

        def fake_send(sess, req, **kwargs):
            auth = req.headers['Authorization']
            self.assertEqual(auth, 'Bearer {}'.format(token['access_token']))
            resp = mock.MagicMock()
            resp.text = 'hi'
            resp.status_code = 200
            return resp

        with app.test_request_context():
            with mock.patch('requests.sessions.Session.send', fake_send):
                resp = client.get('/api/user')
                self.assertEqual(resp.text, 'hi')

                # trigger ctx.authlib_client_oauth_token
                resp = client.get('/api/user')
                self.assertEqual(resp.text, 'hi')
コード例 #2
0
    def test_init_app_params(self):
        app = Flask(__name__)
        oauth = OAuth()
        oauth.init_app(app, SimpleCache())
        self.assertIsNotNone(oauth.cache)
        self.assertIsNone(oauth.update_token)

        oauth.init_app(app, update_token=lambda o: o)
        self.assertIsNotNone(oauth.update_token)
コード例 #3
0
    def test_init_app_later(self):
        app = Flask(__name__)
        app.config.update({
            'DEV_CLIENT_ID': 'dev',
            'DEV_CLIENT_SECRET': 'dev',
        })
        oauth = OAuth()
        remote = oauth.register('dev')
        self.assertRaises(RuntimeError, lambda: oauth.dev.client_id)
        oauth.init_app(app)
        self.assertEqual(oauth.dev.client_id, 'dev')
        self.assertEqual(remote.client_id, 'dev')

        self.assertIsNone(oauth.cache)
        self.assertIsNone(oauth.fetch_token)
        self.assertIsNone(oauth.update_token)
コード例 #4
0
ファイル: __init__.py プロジェクト: yaal-fr/canaille
def create_app():
    app = Flask(__name__)
    app.config.from_envvar("CONFIG")
    app.static_folder = "../../canaille/static"

    oauth = OAuth()
    oauth.init_app(app)
    oauth.register(
        name="yaal",
        client_id=app.config["OAUTH_CLIENT_ID"],
        client_secret=app.config["OAUTH_CLIENT_SECRET"],
        server_metadata_url=get_well_known_url(app.config["OAUTH_AUTH_SERVER"],
                                               external=True),
        client_kwargs={"scope": "openid profile email groups"},
    )

    @app.route("/")
    def index():
        return render_template("index.html",
                               user=session.get("user"),
                               name=app.config["NAME"])

    @app.route("/login")
    def login():
        return oauth.yaal.authorize_redirect(
            url_for("authorize", _external=True))

    @app.route("/authorize")
    def authorize():
        token = oauth.yaal.authorize_access_token()
        userinfo = oauth.yaal.parse_id_token(token)
        session["user"] = userinfo
        flash("You have been successfully logged in.", "success")
        return redirect(url_for("index"))

    @app.route("/logout")
    def logout():
        try:
            del session["user"]
        except KeyError:
            pass

        flash("You have been successfully logged out.", "success")
        return redirect(url_for("index"))

    return app
コード例 #5
0
class FlaskOAuth2Client:
    def init_app(
            self, app,
            hydra_url: str,
            client_id: str,
            client_secret: str,
            scope: list[str],
            cache: Redis,
    ):
        self.hydra_url = hydra_url
        self.client_id = client_id
        self.oauth = OAuth(cache=cache, fetch_token=self._fetch_token, update_token=self._update_token)
        self.oauth.register(
            name='hydra',
            access_token_url=f'{hydra_url}/oauth2/token',
            authorize_url=f'{hydra_url}/oauth2/auth',
            userinfo_endpoint=f'{hydra_url}/userinfo',
            client_id=client_id,
            client_secret=client_secret,
            client_kwargs={'scope': ' '.join(scope)},
        )
        self.oauth.init_app(app)

    def login_redirect(self, redirect_uri, **kwargs):
        """Return a redirect to the Hydra authorization endpoint."""
        return self.oauth.hydra.authorize_redirect(redirect_uri, **kwargs)

    def login_callback(self):
        """Save the token and log the user in."""
        token = self.oauth.hydra.authorize_access_token()
        userinfo = self.oauth.hydra.userinfo()
        user_id = userinfo['sub']

        if not (token_model := Session.get(OAuth2Token, (self.client_id, user_id))):
            token_model = OAuth2Token(client_id=self.client_id, user_id=user_id)

        token_model.token_type = token.get('token_type')
        token_model.access_token = token.get('access_token')
        token_model.refresh_token = token.get('refresh_token')
        token_model.id_token = token.get('id_token')
        token_model.expires_at = token.get('expires_at')
        token_model.save()

        user = Session.get(User, user_id)
        login_user(user)
コード例 #6
0
    def test_request_with_refresh_token(self):
        app = Flask(__name__)
        app.secret_key = '!'
        oauth = OAuth()

        expired_token = {
            'token_type': 'Bearer',
            'access_token': 'expired-a',
            'refresh_token': 'expired-b',
            'expires_in': '3600',
            'expires_at': 1566465749,
        }
        oauth.init_app(app, fetch_token=lambda name: expired_token)
        client = oauth.register(
            'dev',
            client_id='dev',
            client_secret='dev',
            api_base_url='https://i.b/api',
            access_token_url='https://i.b/token',
            refresh_token_url='https://i.b/token',
            authorize_url='https://i.b/authorize'
        )

        def fake_send(sess, req, **kwargs):
            if req.url == 'https://i.b/token':
                auth = req.headers['Authorization']
                self.assertIn('Basic', auth)
                resp = mock.MagicMock()
                resp.json = get_bearer_token
                resp.status_code = 200
                return resp

            resp = mock.MagicMock()
            resp.text = 'hi'
            resp.status_code = 200
            return resp

        with app.test_request_context():
            with mock.patch('requests.sessions.Session.send', fake_send):
                resp = client.get('/api/user', token=expired_token)
                self.assertEqual(resp.text, 'hi')
コード例 #7
0
    jwt_refresh_token_required,
)
from flask_cors import CORS, cross_origin
import re
import os
import smtplib
import imghdr
from email.message import EmailMessage
from itsdangerous import URLSafeTimedSerializer, BadTimeSignature, SignatureExpired
from authlib.integrations.flask_client import OAuth
import json

oauth = OAuth()

app = Flask(__name__)
oauth.init_app(app)
app.secret_key = "markus"
setup_db(app,
         database_path="postgresql://*****:*****@134.122.78.140:5432/register")
jwt = JWTManager(app)
db = SQLAlchemy(app)
CORS(app, resources={r"/*": {"origins": "*"}})
api = Api(
    app,
    version="1.0",
    title="TodoMVC API",
    description="A simple TodoMVC API",
)
bcrypt = Bcrypt()

oauth.register(
コード例 #8
0
ファイル: __init__.py プロジェクト: jinjamator/jinjamator
class AuthLibAuthProvider(AuthProviderBase):
    def __init__(self, app=None):
        super(AuthLibAuthProvider, self).__init__(app)
        if self._app:
            self._oauth = OAuth(self._app)
        else:
            self._oauth = OAuth()
        self._name = None
        self._provider = None
        self._type = "authlib"
        self._display_name = "Authlib Login"

    def init_app(self, app):
        """
        Init oauth instance within Flask
        """
        self._app = app
        self._oauth.init_app(app)

    def register(self, **kwargs):
        """
        Register openid connect provider
        """

        self._name = kwargs.get("name")

        self._oauth.register(**kwargs)

    def login(self, request):
        """
        Start openid connect login procedure
        """
        if self._redirect_uri:
            redirect_uri = self._redirect_uri
        else:
            redirect_uri = url_for("api.aaa_auth", _external=True)
            self._redirect_uri = redirect_uri

        self._log.debug(
            f"Start openid connect login procedure via oidc provider {self._name}"
        )
        self._provider = getattr(self._oauth, self._name)
        return self._provider.authorize_redirect(redirect_uri)

    def authorize(self, request):
        if self._provider:
            self._access_token = self._provider.authorize_access_token()
            self._id_token = self._provider.parse_id_token(self._access_token)
            self._log.debug(self._id_token)
            self._username = self._id_token.get("preferred_username",
                                                self._id_token.get("name"))
            if not self._username:
                abort(500, "Did not get a username from token")
            user = User.query.filter_by(username=self._username).first()
            if user is None:
                self._log.info(
                    f"username {self._username} not found in local database -> creating"
                )
                user = User(username=self._username)
                user.name = self._id_token["name"]

            else:
                self._log.info(
                    f"username {self._username} found in local database")
            user.aaa_provider = self._name
            user.password_hash = user.hash_password("".join(
                random.SystemRandom().choice(string.ascii_letters +
                                             string.digits) for _ in range(128)
            ))  # generate max len random secure password on each login
            db.session.add(user)
            db.session.commit()
            user = User.query.filter_by(username=self._username).first()

            upstream_token = Oauth2UpstreamToken(user_id=user.id,
                                                 aaa_provider=self._name,
                                                 **self._access_token)
            db.session.merge(upstream_token)
            db.session.commit()

            self._user = user

            return True
        else:
            self._log.warn(
                f"AAA provider {self._name} has not been initialized properly")
        return False

    def get_token(self):
        now = timegm(datetime.utcnow().utctimetuple())
        db_token = JinjamatorToken.query.filter_by(
            user_id=self._user.id).first()

        if db_token:
            if self._user.verify_auth_token(db_token.access_token):
                return db_token.access_token
        upstream_token = Oauth2UpstreamToken.query.filter_by(
            user_id=self._user.id).first()

        if upstream_token.expires_at < now:
            log.debug(
                f"upstream token {upstream_token.expires_at} for user {self._user.id} expired {now}, refusing to generate a new local one"
            )
            return False
        else:
            log.debug(
                f"upstream token ({upstream_token.expires_at}) for user {self._user.id} valid ({now}) ttl {upstream_token.expires_at - now}"
            )
        log.debug(f"generating new token for user_id: {self._user.id}")
        return self._user.generate_auth_token().access_token
コード例 #9
0
class OAuthModule(bp.AuthModule):
    def __init__(self, app, bp):
        super(OAuthModule, self).__init__(app, bp)
        self.oauth = OAuth()
        self.oauth.init_app(app)
        self.app = self.register_oauth(self.oauth, app)
        bp.route("/login", methods=["POST"])(self.login)
        bp.route("/authorize", methods=["GET"])(self.authorize)

    @abc.abstractmethod
    def register_oauth(self, oauth, app):
        pass

    @abc.abstractmethod
    def get_login_form_button_text(self):
        pass

    @overrides
    def is_flat(self) -> bool:
        return True

    @overrides
    def can_manage_users(self) -> bool:
        return False

    @overrides
    def get_login_form(self) -> models.LoginForm:
        return models.LoginForm([], self.get_login_form_button_text())

    def login(self) -> Response:
        if "return_to" in request.args:
            redirect = self.app.authorize_redirect(
                request.args.get("return_to"), response_type="token")
        else:
            redirect = self.app.authorize_redirect(response_type="token")
        return jsonify(redirect.headers["Location"])

    def authorize(self):
        authorization_response = request.full_path + "#" + request.args.get(
            "fragment")
        try:
            token = self.app.fetch_access_token(
                authorization_response=authorization_response)
        except Exception as e:
            traceback.print_exc()
            raise exceptions.SecurityError(description=str(e))
        access_token = token["access_token"]
        secret = current_app.config["VEGAS_CLIENT_SECRET"]
        try:
            decoded = jwt.decode(access_token, secret, verify=False)
            decoded = jwt.decode(access_token,
                                 secret,
                                 verify=True,
                                 audience=decoded["aud"])
        except jwt.exceptions.InvalidTokenError as e:
            traceback.print_exc()
            raise exceptions.SecurityError(description=str(e))
        session["auth"] = {
            "user": OAuthUser(decoded).to_dict(),
            "user_data": decoded,
            "token": token
        }
        log.access_flask_login()
        return jsonify(self.get_logged_in_user())
コード例 #10
0
class OAuthModule(bp.AuthModule):
    def __init__(self,
                 app,
                 bp,
                 secret,
                 algorithms: typing.List[str] = ["HS256"]):
        super(OAuthModule, self).__init__(app, bp)
        self.oauth = OAuth()
        self.oauth.init_app(app)
        self.app = self.register_oauth(self.oauth, app)
        self.secret = secret
        self.algorithms = algorithms
        bp.route("/login", methods=["POST"])(self.login)
        bp.route("/authorize", methods=["GET"])(self.authorize_get)
        bp.route("/authorize", methods=["POST"])(self.authorize_post)
        auth.verify_token_callback = lambda t: self.verify_token(t)

    @abc.abstractmethod
    def register_oauth(self, oauth, app):
        pass

    @abc.abstractmethod
    def get_login_form_button_text(self):
        pass

    @overrides
    def is_flat(self) -> bool:
        return True

    @overrides
    def can_manage_users(self) -> bool:
        return False

    @overrides
    def get_login_form(self) -> models.LoginForm:
        return models.LoginForm([], self.get_login_form_button_text())

    @auth.login_required(optional=True)
    @overrides
    def get_logged_in_user(self):
        # if user set in cookie, use that
        user = super(OAuthModule, self).get_logged_in_user()
        if user != None:
            return user

        # otherwise check bearer auth
        ret = auth.current_user()
        if ret != None:
            (token, user) = ret
            if user != None:
                LOGGER.info(
                    "User has logged in via bearer auth; setting session.")
                self._update_session(user, token)

        return super(OAuthModule, self).get_logged_in_user()

    def login(self) -> Response:
        if "return_to" in request.args:
            redirect = self.app.authorize_redirect(
                request.args.get("return_to"), response_type="token")
        else:
            redirect = self.app.authorize_redirect(response_type="token")
        return jsonify(redirect.headers["Location"])

    def make_user(self, decoded: dict) -> OAuthUser:
        return OAuthUser(decoded, id_field="sub")

    def verify_token(self, access_token: str) -> OAuthUser:
        if not access_token:
            return None
        LOGGER.info("Verifying token: \"%s\"", access_token)
        try:
            decoded = jwt.decode(access_token,
                                 options={"verify_signature": False})
            decoded = jwt.decode(access_token,
                                 self.secret,
                                 audience=decoded["aud"],
                                 algorithms=self.algorithms)
        except jwt.exceptions.InvalidTokenError as e:
            traceback.print_exc()
            sys.stderr.flush()
            raise exceptions.SecurityError(description=str(e))
        LOGGER.info("Decoded and validated token: {}".format(decoded))
        return ({"access_token": access_token}, self.make_user(decoded))

    def _update_session(self, user: OAuthUser, token: dict):
        session["auth"] = {
            "user": user.to_dict(),
            "user_data": user.data,
            "token": token
        }
        log.access_flask_login()

    def _authorize(self, authorization_response):
        try:
            token = self.app.fetch_access_token(
                authorization_response=authorization_response)
        except Exception as e:
            traceback.print_exc()
            sys.stderr.flush()
            raise exceptions.SecurityError(description=str(e))
        (_, user) = self.verify_token(token["access_token"])
        self._update_session(user, token)
        return jsonify(self.get_logged_in_user())

    def authorize_post(self):
        body = request.get_json()
        if not body:
            raise exceptions.BadRequest()
        LOGGER.info("Received authorize POST with body {}".format(body))
        authorization_response = request.full_path + "#" + urllib.parse.urlencode(
            body)
        return self._authorize(authorization_response)

    def authorize_get(self):
        LOGGER.info("Received authorize GET with fragment {}".format(
            request.args.get("fragment")))
        authorization_response = request.full_path + "#" + request.args.get(
            "fragment")
        return self._authorize(authorization_response)
コード例 #11
0
def create_app():
    # Configuración inicial de la app
    app = Flask(__name__)
    cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
    app.config.from_object(Config)
    fa = FontAwesome(app)
    app.config['SESSION_TYPE'] = 'filesystem'
    app.config['UPLOAD_FOLDER'] = 'app/static/uploads'
    Session(app)

    # OAuth2
    oauth = OAuth()
    oauth.init_app(app)
    google = oauth.register(
        name = 'google',
        client_id = '593639469284-m7lqdnnjqrsou05rjv5mm7cda944cdg2.apps.googleusercontent.com',
        client_secret = 'tX5Zvj88bp1La0OuE1ubYvLN',
        access_token_url = 'https://accounts.google.com/o/oauth2/token',
        access_token_params = None,
        authorize_url= 'https://accounts.google.com/o/oauth2/auth',
        authorize_params= None,
        api_base_url='https://www.googleapis.com/oauth2/v1/',
        client_kwargs={'scope': 'openid profile email'},
    )

    @app.route('/login_with_google')
    def login_with_google():
        google = oauth.create_client('google')
        redirect_uri = url_for('authorize', _external=True)
        return google.authorize_redirect(redirect_uri)

    @app.route('/authorize')
    def authorize():
        google = oauth.create_client('google')
        token = google.authorize_access_token()
        resp = google.get('userinfo')
        resp.raise_for_status()
        profile = resp.json()
        # do something with the token and profile
        if User.get_by_email(profile['email']):
            session['usuario'] = User.get_by_email(profile['email'])
        return redirect('/')
    

    # Configuracion de la BD
    app.secret_key = 'hola'
    app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://" + \
        Config.DB_USER+":"+Config.DB_PASS+"@"+Config.DB_HOST+"/"+Config.DB_NAME
    db.init_app(app)

    app.config['SESSION_TYPE'] = 'filesystem'
    Session(app)

    # Autenticacion
    app.add_url_rule('/login', 'login', user.login, methods=["GET", "POST"])
    app.add_url_rule('/logout', 'logout', user.logout)

    # Endpoints para api de centros
    app.add_url_rule('/api/centros', 'api_centros',
                     centros.mostrar_centros, methods=["GET"])
    app.add_url_rule('/api/centros/page/<int:page>', 'api_centros',
                     centros.mostrar_centros, methods=["GET"])
    app.add_url_rule('/api/centros/<int:id>', 'api_centro', centros.mostrar_centro, methods=["GET"])
    app.add_url_rule('/api/centros/todos', 'mostrar_todos_centros', centros.mostrar_todos_centros, methods=["GET"])
    app.add_url_rule('/api/crear_centro', 'api_crear_centro',
                     centros.cargarCentros, methods=["GET", "POST"])

    # Endpoints para api de turnos
    app.add_url_rule('/api/centros/id_centro/<int:id_centro>/turnos_disponibles/fecha=<fecha>',
                     'turnos_disponibles', turnos.turnos_disponibles, methods=["POST", "GET"])
    app.add_url_rule('/api/centros/id_centro/<int:id_centro>/reserva', 'pedir_reserva',
        turnos.pedir_reserva, methods=["POST", "GET"])

    # Endpoints para api de estadisticas
    app.add_url_rule('/api/estadisticas/tipos', 'centros_por_tipos', centros.centros_por_tipos, methods=["GET"])
    app.add_url_rule('/api/estadisticas/top10_centros_del_mes', 'top10_centros_del_mes', centros.top10_centros_del_mes, methods=["GET"])
    app.add_url_rule('/api/estadisticas/total_turnos_del_mes', 'total_turnos_del_mes', centros.total_turnos_del_mes, methods=["GET"])

    # Endpoints para Configuracion del Sitio
    app.add_url_rule('/configuracion/vista_configuracion', 'vista_configuracion',
                     config.vista_configuracion, methods=["POST", "GET"])
    # Endpoints para centros
    app.add_url_rule('/centros', 'centros',
                     centros_de_ayuda.go_index, methods=["POST", "GET"])
    app.add_url_rule('/centros/page/<int:page>', 'centros',
                     centros_de_ayuda.go_index, methods=["POST", "GET"])
    app.add_url_rule('/centros/nombre/<nombre>/estado/<estado>/page/<int:page>',
                     'centros', centros_de_ayuda.go_index, methods=["POST", "GET"])
    app.add_url_rule('/centros/crear_centro', 'crear_centro',
                     centros_de_ayuda.crear_centro,  methods=["POST", "GET"])
    app.add_url_rule('/centros/editar_centro/<id>', 'editar_centro',
                     centros_de_ayuda.editar_centro, methods=['POST', 'GET'])
    app.add_url_rule('/centros/borrar_centro/<id>', 'borrar_centro',
                     centros_de_ayuda.borrar_centro, methods=['POST', 'GET'])
    app.add_url_rule('/centros/aprobar_centro/<id>', 'aprobar_centro',
                     centros_de_ayuda.aprobar_centro,  methods=["POST", "GET"])
    app.add_url_rule('/centros/rechazar_centro/<id>', 'rechazar_centro',
                     centros_de_ayuda.rechazar_centro,  methods=["POST", "GET"])
    app.add_url_rule('/centros/publicar_centro/<id>', 'publicar_centro',
                     centros_de_ayuda.publicar_centro,  methods=["POST", "GET"])
    app.add_url_rule('/centros/despublicar_centro/<id>', 'despublicar_centro',
                     centros_de_ayuda.despublicar_centro,  methods=["POST", "GET"])
    app.add_url_rule('/centros/mostrar_centro/<id>', 'mostrar_centro',
                     centros_de_ayuda.mostrar_centro,  methods=["POST", "GET"])

    # Endpoints para Usuarios
    app.add_url_rule('/usuario/edit_usuario/<id>', 'edit_usuario',
                     user.edit_usuario, methods=['POST', 'GET'])
    app.add_url_rule('/usuario/index_usuario', 'index_usuario',
                     user.index_usuario, methods=["POST", "GET"])
    app.add_url_rule('/usuario/crear_usuario', 'crear_usuario',
                     user.crear_usuario, methods=["POST", "GET"])
    app.add_url_rule("/usuarios/borrar_usuario/<id>",
                     'borrar_usuario', user.borrar, methods=['GET'])
    app.add_url_rule("/usuarios/borrar_usuario_por_nombre/<nombre>",
                     'borrar_usuario_por_nombre', user.borrar_por_nombre, methods=['GET'])
    app.add_url_rule('/usuarios/activar/<id>', 'activar',
                     user.activar,  methods=['POST', 'GET'])
    app.add_url_rule('/usuarios/desactivar/<id>', 'desactivar',
                     user.desactivar,  methods=['POST', 'GET'])
    app.add_url_rule('/usuarios/page/<int:page>', 'index_usuario',
                     user.index_usuario, methods=["POST", "GET"])
    app.add_url_rule('/usuarios/nombre/<nombre>/estado/<estado>/page/<int:page>',
                     'index_usuario', user.index_usuario, methods=["POST", "GET"])

    # Endpoints para Turnos
    app.add_url_rule('/turnos_para_centro/index_turno', 'index_turno',
                     turnos_para_centro.index_turno, methods=["POST", "GET"])
    app.add_url_rule('/turnos_para_centro/page/<int:page>', 'index_turno',
                     turnos_para_centro.index_turno, methods=["POST", "GET"])
    app.add_url_rule('/turnos_para_centro/index_turno',
                     'index_turno', turnos_para_centro.index_turno, methods=["POST", "GET"])
    app.add_url_rule('/turnos_para_centro/index_turno/id/<id>',
                     'index_turno', turnos_para_centro.index_turno, methods=["POST", "GET"])
    app.add_url_rule('/turnos_para_centro/page/<int:page>/id/<id>', 'index_turno',
                     turnos_para_centro.index_turno, methods=["POST", "GET"])
    app.add_url_rule('/turnos_para_centro/email/<email>/page/<int:page>',
                     'index_turno', turnos_para_centro.index_turno, methods=["POST", "GET"])
    app.add_url_rule('/turnos_para_centro/crear_turno', 'crear_turno',
                     turnos_para_centro.crear_turno, methods=["POST", "GET"])
    # Modificacion de turnos 04 February 2021 (Thursday)
    app.add_url_rule('/turnos_para_centro/crear_turno/<int:id_centro>', 'crear_turno',
                     turnos_para_centro.crear_turno, methods=["POST", "GET"])
    app.add_url_rule('/turnos_para_centro/crear_turno/<int:id_centro>/fecha=<fecha>', 'crear_turno_para_fechax',
                     turnos_para_centro.crear_turno_para_fecha, methods=["POST", "GET"])
    # Modificacion de turnos 06 February 2021 (Saturday)
    app.add_url_rule('/turnos_para_centro/crear_turno', 'crear_turno_para_fecha',
                     turnos_para_centro.crear_turno_para_fecha, methods=["POST"])
    # /04 February 2021 (Thursday)
    app.add_url_rule('/turnos_para_centro/editar_turno/<id>', 'editar_turno',
                     turnos_para_centro.editar_turno, methods=["POST", "GET"])
    app.add_url_rule('/turnos_para_centro/borrar_turno/<id>', 'borrar_turno',
                     turnos_para_centro.borrar_turno, methods=["POST", "GET"])
    app.add_url_rule('/turnos_para_centro/sacar_turno/<id>', 'sacar_turno',
                     turnos_para_centro.sacar_turno, methods=["POST", "GET"])

    # Manejo de errores
    @app.errorhandler(404)
    def page_not_found(e):
        return render_template('errores/404.html'), 404

    @app.errorhandler(503)
    def page_not_found(e):
        return render_template('errores/503.html'), 503

    @app.errorhandler(401)
    def page_not_found(e):
        return render_template('errores/401.html'), 401

    @app.errorhandler(403)
    def page_not_found(e):
        return render_template('errores/403.html'), 403

    @app.route('/')
    def index():
        if permisos.sitio_cerrado() and permisos.no_es_admin():
            abort(503)
        configuracion = Configuracion.get_config()
        return render_template('index.html', configuracion=configuracion)
    return app