* Plugins and actions need to work better * Plugins should be able to create model classes * So should applications * Plugins can add columns to model classes * Plugins can add logic to model classes (before_*, after_* hooks) * Plugins should be able to add properties to columns * The app always overrides plugins * Plugins are loaded and evaluated in order * Models should become mixins when appropriate - But if the app doesn't define one, they can create classes/tables #' The plugins we want in our ponyverse: * ::Users * ::Users::Identity::EmailedToken * ::UsernamePassword * ::OpenID * ::Certs * ::{Assertion,Kerberos,...} * ::ResetIdentity (change password for any identity once logged in / add identity) * ::Users::Signup * ::Users::Login * ::Users::EmailAddress ::Users * unique ID * created_date, update_date, created_by, updated_by * display_name field (which you can force to something -- e.g. email, openid, name from cert) * (Jifty::Record _brief_description returns this?) * last_login (?) * Do superuser and nobody live in the database? (That's authz) Where do identity plugins hook? * Add columns * Get credentials, return: * These are valid * These are invalid * Other auth error ``I don't know'' * bounce trips go through continuations * load_by_unique_id * ::Login * /login => * list of identity types * for each, fields for login columns declared by the ::Identity::Foo plugin * submit button * Login action * load_by_unique_id * if the user doesn't exist, callback (to signup) or error * Passes credentials to the identity plugin's auth method * Identities that need confirmation error here if needed * frob the session as appropriate * frob CurrentUser * Adds Dispatcher variables * Logout action * frob the session and current user * dispatcher rule on /logout redirects * ::Signup * Signup action * verifies credentials - validates fields (inc. uniqueness) * Creates a record * Add a message, and push the user to the login page with a filled-out login action * What do ``mixins'' *mean*? * We want injection, not actual mixins ----- Where is this going to be hard? ----- * Mixing columns into users * Getting the autogenerated actions to DTRT * hooks look kinda like Plagger * If there are multiple plugin models with no app model, they all get mixed into the null model ----- Username/password plugin ------ # Model (Jifty::Plugin::User::Identity::UsernamePassword::Model::User) column 'username' => type is 'text', is unique; column 'password' => type is 'text', render_as 'Password', filters are qw(Jifty::DBI::Filter::SaltHash); sub password_is { my $self = shift; my $pass = shift; return undef unless $self->_value('password'); my ($hash, $salt) = @{$self->_value('password')}; return 1 if ( $hash eq Digest::MD5::md5_hex($pass . $salt) ); return undef; } # ``exports'' sub load_by_unique_id { my $self = shift; my %args = (username => undef, @_); return $self->load_by_columns(username => $args{username}); } sub validate_credentials { my $self = shift; my %args = (username => undef, @_); return unless $self->id; return $self->password_is($args{password}); } # Jifty::Plugin::User::Identity::UsernamePassword::Action::Login param username => render_as 'Text'; param password => render_as 'Password'; # Login plugin Action::Login sub check_credentials { my $self = shift; my $userobj = MyApp::Model::User->new; my $user; foreach my $identity_type ($userobj->identity_plugins) { if($userobj->($identity_type . "::load_by_unique_id")($self->argument_values)) { if($userobj->($identity_type . "::validate_credentials")($self->argument_values)) { ... } else { ... } } } }