Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AttributeError: 'dict' object has no attribute 'create_cookie' #849

Open
hazho opened this issue Mar 16, 2023 · 3 comments
Open

AttributeError: 'dict' object has no attribute 'create_cookie' #849

hazho opened this issue Mar 16, 2023 · 3 comments

Comments

@hazho
Copy link

hazho commented Mar 16, 2023

I am having a some issues implementing OP, the following is my implementation:

from flask import Flask, request
from oic.oic.provider import Provider
from oic.utils.keyio import KeyBundle
from oic.utils.authn.authn_context import AuthnBroker
from oic.utils.userinfo import UserInfo
from oic.utils.authz import AuthzHandling
from oic.utils.authn.client import ClientSecretBasic
from flask_pyoidc.provider_configuration import ClientRegistrationInfo
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes

app = Flask(__name__)

# Generate RSA key pair
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048
)
public_key = private_key.public_key()

# Save private key to a file
with open('private_key.pem', 'wb') as f:
    f.write(private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption()
    ))

with open('private_key.pem', 'rb') as f:
  # Load private key into KeyBundle
  # Load private key into KeyBundle
  global keys
  keys = KeyBundle(source='file://private_key.pem', fileformat='pem')
  keys.append({'kty': 'RSA', 'key': public_key})

from oic.utils.authn.client import CLIENT_AUTHN_METHOD

# Initialize Provider with required arguments
authn_broker = AuthnBroker()

authn_broker.add('client_secret_jwt', CLIENT_AUTHN_METHOD)

# Instantiate ClientSecretBasic and add it to the authn_broker
client_secret_basic = ClientSecretBasic()
authn_broker.add('client_secret_basic', client_secret_basic)

authz = AuthzHandling()
userinfo = UserInfo()
provider = Provider('my-server',
                    'sqlite:///my-server.db',
                    keys,
                    authn_broker=authn_broker,
                    authz=authz,
                    userinfo=userinfo,
                    client_authn=client_secret_basic)

# Route for handling authorization requests
@app.route('/authorize')
def authorize():
    # Get authorization request parameters
    request_args = request.args
    client_id = request_args.get('client_id')
    redirect_uri = request_args.get('redirect_uri')
    response_type = request_args.get('response_type')

    # Validate authorization request parameters
    if not client_id:
        return 'Error: client_id is required'
    if not redirect_uri:
        return 'Error: redirect_uri is required'
    if not response_type:
        return 'Error: response_type is required'

    # Create authorization response
    auth_req = provider.authorization_request(
        request_args=request_args,
        cookie=request.cookies,
        headers=request.headers
    )
    return auth_req(request)

# Route for handling token requests
@app.route('/token')
def token():
    # Get token request parameters
    request_args = request.args
    grant_type = request_args.get('grant_type')
    code = request_args.get('code')
    redirect_uri = request_args.get('redirect_uri')

    # Validate token request parameters
    if not grant_type:
        return 'Error: grant_type is required'
    if grant_type != 'authorization_code':
        return 'Error: invalid grant_type'
    if not code:
        return 'Error: code is required'
    if not redirect_uri:
        return 'Error: redirect_uri is required'

    # Create token response
    token_req = provider.token_request(
        request_args=request_args,
        cookie=request.cookies,
        headers=request.headers
    )
    return token_req(request)

# Route for registering new clients
@app.route('/register', methods=['POST'])
def register_client():
    # Get client registration request parameters
    request_data = request.get_json()
    client_id = request_data.get('client_id')
    client_secret = request_data

    client_info = ClientRegistrationInfo(
        client_id=client_id,
        client_secret=client_secret,
        redirect_uris=[request_data.get('redirect_uri')],
        response_types=[request_data.get('response_type')],
        grant_types=[request_data.get('grant_type')],
        token_endpoint_auth_method=request_data.get('token_endpoint_auth_method', 'client_secret_basic'),
        scope=request_data.get('scope'),
        contacts=request_data.get('contacts'),
        client_preferences=request_data.get('client_preferences')
    )

    # Register new client
    provider.client_registration_info.append(client_info)

    return 'Client registered successfully'

if name == 'main': app.run(debug=True)

and the following is the error:

site-packages/oic/oauth2/provider.py", line 244, in __init__
   self.cookie_func = self.authn_broker[0][0].create_cookie
AttributeError: 'dict' object has no attribute 'create_cookie'
@tpazderka
Copy link
Collaborator

You are passing in a CLIENT_AUHTN_METHOD into the broker which is a dict. You should pass one of the values inside that dictionaty. The method argument should be a callable.

And if I am not mistaken, you are also using the Client authentication methods, but the broker is intended for user authentication methods.

Also, the Provider class has methods for most of the stuff you are doing manually (authorization_endpoint, token_endpoint ...)

@hazho
Copy link
Author

hazho commented Mar 17, 2023

is there any complete example for an OP server using flask?
without brokers...!
or is there a documentation on how to build a simple OP server? the one in the readthedoc is not providing a code sample...!

@tpazderka
Copy link
Collaborator

There are some examples in the examples directory, but none are in Flask AFAIK.

You will need a broker since you need to get some user authentication. You should look into oic.utils.authn.user module for something that fits your needs (there is a NoAuthn)for testing purposes).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants