Giter Site home page Giter Site logo

engineauth's People

Contributors

alecdotico avatar dpetrovics avatar hanasoo avatar hfwang avatar kylefinley avatar spaceflyer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

engineauth's Issues

Can't override User model.

I think there is some problem somewhere I can't see. I have inherited the engineauth.models.User to add a lot of non-auth-related attributes, methods and stuff and I need to use it, but it fails to recognize my model and, when I try to run with my model set, the app just ignores my appengine_config.py and stores everything in the engineauth.models.User model.

my appengine_config.py:

engineauth = {
    'secret_key': 'Very nice secret key.',
    'user_model': 'custom_models.Account',
    'login_uri': '/_login',
    'base_uri': '/_auth',
}
engineauth['provider.auth'] = {
    'user_model': 'custom_models.Account',
    'session_backend': 'datastore',
}

(I also tried changin' only the first one of the 'user_model' keys up there)
(Besides this, I also tried to change the 'user_model' key at the engineauth/config.py file, but nothing came out of it)

my standalone file custom_models.py:

class Account(engineauth.models.User):
    username = ndb.StringProperty()
    # other stuff

so, what's it? Is it a bug? I really tried to read the source, but I'm kind of a newbie.

maybe the import is failing in middleware.py, at:

    def _get_user_class(self):
        try:
            return utils.import_class(self._config['user_model'])
        except Exception:
            return models.User

but I'm too bad at debbuging to verify it. Sorry. Thank you.

User id not converted to string when passed to Session

This still baffles me, honestly.
User.get_id returns a string. Clear enough.
However, when I try to log with an existing user, in middleware.py line 79:

self.session.user_id = self.user.get_id()

the id is a long... and that's where it throws an exception, which gets recorded in the session messages.

For now I am converting the id explicitly, but any ideas why this happens and how it could be solved would be great.

RFC-5849: CSRF and UI Redress

1)Cross-Site Request Forgery:
In "RFC-5849 4.13. Cross-Site Request Forgery (CSRF)" (http://tools.ietf.org/html/rfc5849#section-4.13) it states that a Cross-Site Request Forgery cannot be used to initiate an OAuth negotiation.

This attack could be triggered an a hidden iframe which triggers the following GET request:

<iframe src=http://engineauth.scotchmedia.com/auth/google />

If the google oauth user account has already been used to authenticate then the browser will automatically authenticate with engineauth.scotchmedia.com. At this point an attacker could deliver an XSS, CSRF or Clickjacking exploit to an authenticated website.

To mitigate this issue a synchronization token should be present within the OAuth login request.

More Information on preventing CSRF:
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet

  1. UI Redress:
    The example application running at engineauth.scotchmedia.com is vulnerable to UI Redress. In "RFC-5849 section 4.14. - User Interface Redress" it stats that the buttons used to initiate the OAuth negotiation need to be protected against Clickjacking attacks.

This vulnerability can be mitigated by setting the "x-frame-options: sameorigin" HTTP header.

More Information on preventing clickjacking:
https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet

Session Management

This bug relates to the confidentiality and performance of the sessions used by engineauth. In short, webapp2_extras.sessions is more secure and flexible.

The following is the HTTP response produced at the end of the OAuth negotiation which establishes the authenticated session state:

HTTP/1.1 307 Temporary Redirect
set-cookie: _eauth="eyJ1c2VyX2lkIjoiNTczMzk1MzEzODg1MTg0MCIsInNlc3Npb25faWQiOiI1NzMzOTUzMTM4ODUxODQwIn0\075|1369787314|a370913d395205858ebd0c3b5f4809f18b26aa4a"; Path=/
location: http://localhost:8080/
content-type: text/html; charset=UTF-8
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Cache-Control: no-cache
Content-Length: 258
Server: Development/2.0
Date: Wed, 29 May 2013 00:28:34 GMT

This set-cookie http response header is not setting the HTTPOnly and Secure cookie flags. These two flags are intended to prevent the compromise of the session id. Having the HTTPOnly flag set means that an attacker cannot read this cookie value using an XSS payload. The secure cookie flag insures that this cookie value will never be transmitted over an insecure channel. By transmitting the cookie value in plaintext, an attacker can hijack an authenticated session using a tool like Firesheep.

Firesheep:
http://en.wikipedia.org/wiki/Firesheep

Cookie security flags:
https://www.owasp.org/index.php/HttpOnly
https://www.owasp.org/index.php/SecureFlag

Transport layer protection:
https://www.owasp.org/index.php/Top_10_2010-A9-Insufficient_Transport_Layer_Protection

The base64 used in the _eauth cookie value is as follows:
eyJ1c2VyX2lkIjoiNTczMzk1MzEzODg1MTg0MCIsInNlc3Npb25faWQiOiI1NzMzOTUzMTM4ODUxODQwIn0\075

This base64 decodes to the following
{"user_id":"5733953138851840","session_id":"5733953138851840"}

The session_id is used to reference a session sate stored in the Google datastore. This design is a blending of session management paradigms.

One paradigm is storing the session state in the Cookie as a serialized object. This value is attacker controlled so it must be protected with an hmac and a secret key. The hmac value in the set-cookie at the top of this post is: a370913d395205858ebd0c3b5f4809f18b26aa4a.

The other paradigm is setting the cookie value to be a large random value. This value alone is used to lookup session sate in the database.

Both paradigms are secure on their own, and there is no security benefit of blending these two approaches. It should be up to the user which method they would like to use. The use of an HMAC means that an efficient RESTful api uses one database lookup per API call. Storing state on the server side reduces bandwidth consumed by the client.

A possible solution to this problem is to expose some of the configuration options used in "webapp2_extras.sessions". For example this class provides three datastore backends, and the ability to add new backends.

The three are "securecookie", "datastore", and "memcached":
(http://webapp-improved.appspot.com/api/webapp2_extras/sessions.html#webapp2_extras.sessions.SessionStore.get_session)

"webapp2_extras.sessions" also exposes the two security related cookie flags by specifying the "secure" and "httponly" using the "cookie_args" parameter.

Admin account in engineauth

Hey, how would you go about creating a simple way to identify an admin user?

Would a simple flag on the User model be enough? I don't know if there are any security risks with this approach...

Password hash funciton

There is a vulnerability related to how passwords are stored. It is referred to as CWE-916: Use of Password Hash With Insufficient Computational Effort:
http://cwe.mitre.org/data/definitions/916.html

On line 59 the generate_password_hash() method is used without specifying a password hash function:
https://github.com/scotch/engineauth/blob/master/engineauth/strategies/password.py

This will default to sha1:
http://webapp-improved.appspot.com/_modules/webapp2_extras/security.html#generate_password_hash

hashlib supports sha256, which is better than sha1 for passwords, however still not suitable. Ideally you want to a heavy KDF funciton such as bcrypt or scrypt.

This is a good read on bcrypt for passwords:
http://security.stackexchange.com/questions/4781/do-any-security-experts-recommend-bcrypt-for-password-storage/6415

I will also file bug with webapp2.

Load Provider Settings from Datastore

Proposed here by Nick R

Developers should be able to store providers settings in the datastore.

Possible implementation details

  1. A request is made to a service i.e. example.com/auth/provider
  2. A check is made to the appengine_config.py.
  3. If no settings are found. A check is made to a NDB provider model.
  4. If no model is found. A new NDB provider model is saved to the datastore with empty settings. This will make it easier for a developer to add settings.

Efficiency

Using NDB models will make the retrieval very efficient. Request will follow this pattern instance => memcache => datastore

Multiple Hosts

To allow for multiple hosts the key for the Providers should use this form domain:provider E.g. example.com:google or example.com.br:google.

Support for google-apiclient 1.3.1

I just discovered this project yesterday. Working through an example with latest Google appengine and over the last few years it appears that apiclient.oauth has been removed. Is my investigation correct?

The stacktrace I am getting using apiclient 1.3.1 is:

Traceback (most recent call last):
File "/home/andrew/src/aah-profile-report/engineauth/utils.py", line 29, in import_class
mod = import(path, fromlist=[klass])
File "/home/andrew/.eclipse/1712548941_linux_gtk_x86_64/plugins/org.python.pydev_4.0.0.201504132356/pysrc/pydev_monkey_qt.py", line 71, in patched_import
File "/home/andrew/src/aah-profile-report/engineauth/strategies/linkedin.py", line 5, in
from engineauth.strategies.oauth import OAuthStrategy
File "/home/andrew/.eclipse/1712548941_linux_gtk_x86_64/plugins/org.python.pydev_4.0.0.201504132356/pysrc/pydev_monkey_qt.py", line 71, in patched_import
File "/home/andrew/src/aah-profile-report/engineauth/strategies/oauth.py", line 2, in
from apiclient.oauth import FlowThreeLegged
File "/home/andrew/.eclipse/1712548941_linux_gtk_x86_64/plugins/org.python.pydev_4.0.0.201504132356/pysrc/pydev_monkey_qt.py", line 71, in patched_import
ImportError: No module named apiclient.oauth
ERROR 2015-06-19 01:19:42,085 cgi.py:122] Traceback (most recent call last):
File "/home/andrew/src/aah-profile-report/helloworld.py", line 34, in
main()
File "/home/andrew/src/aah-profile-report/helloworld.py", line 31, in main
run_wsgi_app(application)
File "/home/andrew/google-cloud-sdk/platform/google_appengine/google/appengine/ext/webapp/util.py", line 99, in run_wsgi_app
run_bare_wsgi_app(add_wsgi_middleware(application))
File "/home/andrew/google-cloud-sdk/platform/google_appengine/google/appengine/ext/webapp/util.py", line 117, in run_bare_wsgi_app
result = application(env, _start_response)
File "/home/andrew/src/aah-profile-report/engineauth/middleware.py", line 144, in call
strategy_class = self._load_strategy(provider)
File "/home/andrew/src/aah-profile-report/engineauth/middleware.py", line 164, in _load_strategy
"'provider.{0}' config dict".format(provider))
Exception

INFO 2015-06-19 01:19:42,142 module.py:790] default: "GET /auth/linkedin HTTP/1.1" 500 -

Notice the import error
ImportError: No module named apiclient.oauth

The current apiclient documentation (and library) make not mention of this package.
https://developers.google.com/api-client-library/python/guide/google_app_engine

Just wondering, if an update to engineauth in the works to support these changes or have I misunderstood something in my research?

App Engine SDK 1.8.3

On 1.8.3, engineauth fails to create a new User on login. On 1.8.1, it works fine. Any intuition on what could be happening here?

Twitter response status for user_info

Thanks for the lib -- I'm having an issue using engineauth for Twitter authentication locally on my machine.

Stepping through with the debugger, the issue seems to be here: https://github.com/scotch/engineauth/blob/master/engineauth/strategies/twitter.py#L25

Here's the res (with x's by potentially sensitive info):

(Pdb) pprint.pprint(res)
{'-content-encoding': 'gzip',
 'cache-control': 'no-cache, no-store, must-revalidate, pre-check=0, post-check=0',
 'content-disposition': 'attachment; filename=json.json',
 'content-length': '4556',
 'content-location': 'https://api.twitter.com/1.1/account/verify_credentials.json',
 'content-type': 'application/json;charset=utf-8',
 'date': 'Thu, 20 Aug 2015 01:34:15 GMT',
 'expires': 'Tue, 31 Mar 1981 05:00:00 GMT',
 'last-modified': 'Thu, 20 Aug 2015 01:34:15 GMT',
 'pragma': 'no-cache',
 'server': 'tsa_a',
 'set-cookie': 'lang=en; Path=/, guest_id=v1%xxxxxxxxxxxxxx; Domain=.twitter.com; Path=/; Expires=Sat, 19-Aug-2017 01:34:15 UTC',
 'status': '200',
 'strict-transport-security': 'max-age=631138519',
 'x-access-level': 'read-write',
 'x-connection-hash': 'xxxxxxxxxxx',
 'x-content-type-options': 'nosniff',
 'x-frame-options': 'SAMEORIGIN',
 'x-rate-limit-limit': '15',
 'x-rate-limit-remaining': '13',
 'x-rate-limit-reset': '1440034769',
 'x-response-time': '33',
 'x-transaction': 'xxxxxxxxxxxxxxx',
 'x-twitter-response-tags': 'BouncerExempt, BouncerCompliant',
 'x-xss-protection': '1; mode=block’}

Even though the status looks to be 200, res.status is evaluating to 200L, not 200. So the error on line 26 is being raised. Any ideas on what could be going on? Seems like its parsing the status into a long?

If I remove the check for status 200, everything works as expected. The session, user, and profile are created in the datastore.

Support for google-apiclient 1.3.1

I just discovered this project yesterday. I am working through an example with latest Google appengine and over the last few years it appears that apiclient.oauth has been removed. Is my investigation correct?

The stacktrace I am getting using apiclient 1.3.1 is:

Traceback (most recent call last):
File "/home/andrew/src/aah-profile-report/engineauth/utils.py", line 29, in import_class
mod = import(path, fromlist=[klass])
File "/home/andrew/.eclipse/1712548941_linux_gtk_x86_64/plugins/org.python.pydev_4.0.0.201504132356/pysrc/pydev_monkey_qt.py", line 71, in patched_import
File "/home/andrew/src/aah-profile-report/engineauth/strategies/linkedin.py", line 5, in
from engineauth.strategies.oauth import OAuthStrategy
File "/home/andrew/.eclipse/1712548941_linux_gtk_x86_64/plugins/org.python.pydev_4.0.0.201504132356/pysrc/pydev_monkey_qt.py", line 71, in patched_import
File "/home/andrew/src/aah-profile-report/engineauth/strategies/oauth.py", line 2, in
from apiclient.oauth import FlowThreeLegged
File "/home/andrew/.eclipse/1712548941_linux_gtk_x86_64/plugins/org.python.pydev_4.0.0.201504132356/pysrc/pydev_monkey_qt.py", line 71, in patched_import
ImportError: No module named apiclient.oauth
ERROR 2015-06-19 01:19:42,085 cgi.py:122] Traceback (most recent call last):
File "/home/andrew/src/aah-profile-report/helloworld.py", line 34, in
main()
File "/home/andrew/src/aah-profile-report/helloworld.py", line 31, in main
run_wsgi_app(application)
File "/home/andrew/google-cloud-sdk/platform/google_appengine/google/appengine/ext/webapp/util.py", line 99, in run_wsgi_app
run_bare_wsgi_app(add_wsgi_middleware(application))
File "/home/andrew/google-cloud-sdk/platform/google_appengine/google/appengine/ext/webapp/util.py", line 117, in run_bare_wsgi_app
result = application(env, _start_response)
File "/home/andrew/src/aah-profile-report/engineauth/middleware.py", line 144, in call
strategy_class = self._load_strategy(provider)
File "/home/andrew/src/aah-profile-report/engineauth/middleware.py", line 164, in _load_strategy
"'provider.{0}' config dict".format(provider))
Exception

INFO 2015-06-19 01:19:42,142 module.py:790] default: "GET /auth/linkedin HTTP/1.1" 500 -

Notice the import error
ImportError: No module named apiclient.oauth

The current apiclient documentation (and library) make not mention of this package.
https://developers.google.com/api-client-library/python/guide/google_app_engine

Just wondering, if an update to engineauth in the works to support these changes or have I misunderstood something in my research?

open redirect vulnerability

engineauth is vulnerable to a open redirect vulnerability.

OWASP Top 10: Unvalidated Redirects and Forwards:
https://www.owasp.org/index.php/Top_10_2010-A10-Unvalidated_Redirects_and_Forwards

PoC exploit, will work authenticated or unauthenticated:
http://engineauth.scotchmedia.com/auth/google?next=http://www.facebook.com

vulnerable code in middleware.py line 96:
def _set_redirect_uri(self):
next_uri = self.GET.get('next')
if next_uri is not None:
self.session.data['_redirect_uri'] = next_uri
set_redirect_uri = _set_redirect_uri

Solution:
Ideal solution: An application should never pass the redirect link as an attacker controlled variable, the session can be used to pass this information.

Dirty hack workaround: Prevent redirection to a different domain, prevent redirection to images.

Profiles are not associated by email

Current version doesn't seem to be associating different profiles by a common (if present) email address. In fact, the model UserEmail (which I believe is the responsible of this association) seems to never be created at all.

I would expect the UserEmail to be created in the following method of the User model:

    @classmethod
        def _get_or_create(cls, auth_id, emails, **kwarg):
            assert isinstance(emails, list), 'Emails must be a list'
            user = cls._find_user(auth_id, emails)
    #        if user and emails is not None:
    #            user._add_emails(emails)
            if user is None:
                user = cls._create_user(auth_id, **kwarg)
            return user

But that part of the code is commented out, and I can't find the reason in the logs. Is it safe to remove the comments?, is the User<-Email->UserProfile association done here, or am I completely clueless?.

Thank you so much!

Authentication and Registration for 2 profiles

Hello,

I am creating a new app engine application. The applications require 2 types of profiles, teachers and students. I know that using your application I can authenticate users but what way you take to separate every type of user???

I need to create a Handler to login and register a new user for student and teacher???

Your model is an Expando?

Best Regards

The raising exception in the last few lines doesn't work

I didn't set 'lib' in my path so an exception occurred:

Traceback (most recent call last):

  File "C:\Users\SpaceFlyer\Dropbox\programming\orderonline\OrderOnline\engineauth\middleware.py", line 162, in _load_strategy

    return utils.import_class(strategy_location)

  File "C:\Users\SpaceFlyer\Dropbox\programming\orderonline\OrderOnline\engineauth\utils.py", line 29, in import_class

    mod = __import__(path, fromlist=[klass])

  File "C:\Users\SpaceFlyer\Dropbox\programming\orderonline\OrderOnline\engineauth\strategies\google.py", line 3, in 

    from apiclient.discovery import build

ImportError: No module named apiclient.discovery

INFO     2014-11-14 02:38:29,122 middleware.py:165] No module named apiclient.discovery

But instead of reporting the above exception, the last few lines generated the following information in app engine console, which is very confusing:

ERROR    2014-11-14 02:29:44,747 wsgi.py:278] 

Traceback (most recent call last):

  File "C:\Program Files (x86)\Google\google_appengine\google\appengine\runtime\wsgi.py", line 266, in Handle

    result = handler(dict(self._environ), self._StartResponse)

  File "C:\Users\SpaceFlyer\Dropbox\programming\orderonline\OrderOnline\engineauth\middleware.py", line 147, in __call__

    strategy_class = self._load_strategy(provider)

  File "C:\Users\SpaceFlyer\Dropbox\programming\orderonline\OrderOnline\engineauth\middleware.py", line 166, in _load_strategy

    "'provider.{0}' config dict".format(provider))

Exception

Example handlers.py is incomplete

In particular, the Account and Password handlers appear to be missing.
It's possible that these are picked up by the middleware module, but it seems unclear if that's the case.

If the example is still a work in progress, it might be worthwhile to add it to your TODO file, or add individual TODOs into example/handlers.py

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.