Skip to content

Commit

Permalink
Merge branch 'next'
Browse files Browse the repository at this point in the history
  • Loading branch information
Marco Otte-Witte committed May 12, 2014
2 parents 3abfea2 + dbc8478 commit ffb042c
Show file tree
Hide file tree
Showing 38 changed files with 297 additions and 143 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
# 0.4.0

* __[BREAKING]__ Ember.SimpleAuth's factories are now registered with
"namespaced" names with Ember's container to avoid conflicts, see #159;
__this requires all references to these factories (e.g.
`authenticatorFactory` in controllers to be prepended with
`'ember-simple-auth-'`).
* __[BREAKING]__ `Ember.SimpleAuth.Authorizers.Devise` now sends the user's
token and email address in one header that's compatible to
[Rails' token auth module](http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html)
* __[BREAKING]__ `Ember.SimpleAuth.Authenticators.Devise` now sends the
(configurable) resource name for session authentication, see #157
* The name of the property that Ember.SimpleAuth injects the session with into
routes and controllers can now be customized, see #159
* fixed `Ember.SimpleAuth.Utils.isSecureUrl` so that it checks the passed URL
not the current location
* improved the instructions for server side setup for ember-simple-auth-devise,
see #155

# 0.3.1

* Fixed a bug where the arguments from session events were not passed to router
Expand Down
2 changes: 1 addition & 1 deletion examples/1-simple.html
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ <h1>Protected Page</h1>
// use the provided mixins in the application route and login controller
App.ApplicationRoute = Ember.Route.extend(Ember.SimpleAuth.ApplicationRouteMixin);
App.LoginController = Ember.Controller.extend(Ember.SimpleAuth.LoginControllerMixin, {
authenticatorFactory: 'authenticator:oauth2-password-grant'
authenticatorFactory: 'ember-simple-auth-authenticator:oauth2-password-grant'
});

// make this route protected
Expand Down
2 changes: 1 addition & 1 deletion examples/2-errors.html
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ <h1>Erroneous Page</h1>
}
});
App.LoginController = Ember.Controller.extend(Ember.SimpleAuth.LoginControllerMixin, {
authenticatorFactory: 'authenticator:oauth2-password-grant'
authenticatorFactory: 'ember-simple-auth-authenticator:oauth2-password-grant'
});

// make these routes protected
Expand Down
2 changes: 1 addition & 1 deletion examples/3-token-refresh.html
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ <h1>Protected Page</h1>
// use the provided mixins in the application route and login controller
App.ApplicationRoute = Ember.Route.extend(Ember.SimpleAuth.ApplicationRouteMixin);
App.LoginController = Ember.Controller.extend(Ember.SimpleAuth.LoginControllerMixin, {
authenticatorFactory: 'authenticator:oauth2-password-grant'
authenticatorFactory: 'ember-simple-auth-authenticator:oauth2-password-grant'
});

// make this route protected
Expand Down
2 changes: 1 addition & 1 deletion examples/4-authenticated-account.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ <h1>Protected Page</h1>
container.register('authenticator:custom', App.CustomAuthenticator);
Ember.SimpleAuth.setup(container, application, {
// configure an authorizer so the accound model can be read from the server
authorizerFactory: 'authorizer:oauth2-bearer'
authorizerFactory: 'ember-simple-auth-authorizer:oauth2-bearer'
});
}
});
Expand Down
4 changes: 2 additions & 2 deletions examples/5-ember-data.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ <h1>Protected Page</h1>
initialize: function(container, application) {
Ember.SimpleAuth.setup(container, application, {
// configure an authorizer so that Ember Data requests get authorized
authorizerFactory: 'authorizer:oauth2-bearer'
authorizerFactory: 'ember-simple-auth-authorizer:oauth2-bearer'
});
}
});
Expand All @@ -131,7 +131,7 @@ <h1>Protected Page</h1>
// use the provided mixins in the application route and login controller
App.ApplicationRoute = Ember.Route.extend(Ember.SimpleAuth.ApplicationRouteMixin);
App.LoginController = Ember.Controller.extend(Ember.SimpleAuth.LoginControllerMixin, {
authenticatorFactory: 'authenticator:oauth2-password-grant'
authenticatorFactory: 'ember-simple-auth-authenticator:oauth2-password-grant'
});

// make these routes protected
Expand Down
4 changes: 2 additions & 2 deletions examples/8-cookie-store.html
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ <h1>Protected Page</h1>
name: 'authentication',
initialize: function(container, application) {
Ember.SimpleAuth.setup(container, application, {
storeFactory: 'session-store:cookie'
storeFactory: 'ember-simple-auth-session-store:cookie'
});
}
});
Expand All @@ -109,7 +109,7 @@ <h1>Protected Page</h1>
// use the provided mixins in the application route and login controller
App.ApplicationRoute = Ember.Route.extend(Ember.SimpleAuth.ApplicationRouteMixin);
App.LoginController = Ember.Controller.extend(Ember.SimpleAuth.LoginControllerMixin, {
authenticatorFactory: 'authenticator:oauth2-password-grant'
authenticatorFactory: 'ember-simple-auth-authenticator:oauth2-password-grant'
});

// make this route protected
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ var global = (typeof window !== 'undefined') ? window : {},
This store will trigger the `'updated'` event when any of its cookies is
changed from another tab or window.
_The factory for this store is registered as `'session-store:cookie'` in
Ember's container.
_The factory for this store is registered as
`'ember-simple-auth-session-store:cookie'` in Ember's container._
@class Cookie
@namespace Stores
Expand Down
2 changes: 1 addition & 1 deletion packages/ember-simple-auth-cookie-store/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ember-simple-auth-cookie-store",
"version": "0.3.1",
"version": "0.4.0",
"description": "A Cookie based store for Ember.SimpleAuth.",
"author": "Marco Otte-Witte",
"license": "MIT"
Expand Down
2 changes: 1 addition & 1 deletion packages/ember-simple-auth-cookie-store/wrap/browser.end
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
global.Ember.SimpleAuth.Stores.Cookie = requireModule('ember-simple-auth-cookie-store').default;

global.Ember.SimpleAuth.initializeExtension(function(container, application, options) {
container.register('session-store:cookie', global.Ember.SimpleAuth.Stores.Cookie);
container.register('ember-simple-auth-session-store:cookie', global.Ember.SimpleAuth.Stores.Cookie);
});
})((typeof global !== 'undefined') ? global : window);
154 changes: 106 additions & 48 deletions packages/ember-simple-auth-devise/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,100 @@ This is an extension to the Ember.SimpleAuth library that provides an
authenticator and an authorizer that are compatible with customized
installations of [Devise](https://github.com/plataformatec/devise).

## Server-side setup

As token authentication is not actually part of Devise anymore, there are some
customizations necessary on the server side (most of this is adapted from
[José Valim's gist on token authentication](https://gist.github.com/josevalim/fb706b1e933ef01e4fb6)).

First, a new column for the authentication token must be added to the users
table:

```ruby
class AddAuthenticationTokenToUser < ActiveRecord::Migration
def change
add_column :users, :authentication_token, :string
end
end
```

That authentication token must be auto-generated by the model on creation:

```ruby
class User < ActiveRecord::Base
before_save :ensure_authentication_token

def ensure_authentication_token
if authentication_token.blank?
self.authentication_token = generate_authentication_token
end
end

private

def generate_authentication_token
loop do
token = Devise.friendly_token
break token unless User.where(authentication_token: token).first
end
end
end
```

By default, Devise's sessions controller only responds to HTML request. In
order for it to work with Ember.SimpleAuth it must also respond to JSON. To
achieve that, define a custom sessions controller (_if HTML responses are not
needed the format handling can be left out of course_):

```ruby
class SessionsController < Devise::SessionsController
def create
respond_to do |format|
format.html { super }
format.json do
self.resource = warden.authenticate!(auth_options)
sign_in(resource_name, resource)
data = {
user_token: self.resource.authentication_token,
user_email: self.resource.email
}
render json: data, status: 201
end
end
end
end
```

and configure Devise to use that controller instead of the default one:

```ruby
MyRailsApp::Application.routes.draw do
devise_for :users, controllers: { sessions: 'sessions' }
end
```

Finally, the Rails application must authenticate users by their authentication
token and email if present:

```ruby
class ApplicationController < ActionController::Base
before_filter :authenticate_user_from_token!

private

def authenticate_user_from_token!
authenticate_with_http_token do |token, options|
user_email = options[:user_email].presence
user = user_email && User.find_by_email(user_email)

if user && Devise.secure_compare(user.authentication_token, token)
sign_in user, store: false
end
end
end
end
```

## The Authenticator

In order to use the Devise authenticator (see the
Expand Down Expand Up @@ -36,67 +130,31 @@ by the `LoginControllerMixin` that the respective controller in the application
needs to include. It also needs to specify the Devise authenticator to be used:

```js
App.LoginController = Ember.Controller.extend(Ember.SimpleAuth.LoginControllerMixin,
{ authenticatorFactory: "authenticator:devise" });
```

As token authentication is not actually part of Devise anymore, there are some
customizations necessary on the server side. In order for the authentication to
work it has to include the user's auth token and email in the JSON response for
session creation:

```ruby
class SessionsController < Devise::SessionsController
def create
resource = resource_from_credentials
data = {
auth_token: resource.authentication_token,
auth_email: resource.email
}
render json: data, status: 201
end
end
App.LoginController = Ember.Controller.extend(Ember.SimpleAuth.LoginControllerMixin, {
authenticatorFactory: 'ember-simple-auth-authenticator:devise'
});
```

## The Authorizer

The authorizer (see the
[API docs for `Authorizers.Devise`](http://ember-simple-auth.simplabs.com/ember-simple-auth-devise-api-docs.html#Ember-SimpleAuth-Authorizers-Devise))
authorizes requests by adding `auth-token` and `auth-email` headers. To use the
authorizer, specify it for Ember.SimpleAuth's setup:
authorizes requests by adding `user_token` and `user_email` properties from the
session in the `Authorization` header:

```
Authorization: Token token="<user_token>", user_email="<user_email>"
```

To use the authorizer, specify it for Ember.SimpleAuth's setup:

```js
Ember.Application.initializer({
name: 'authentication',
initialize: function(container, application) {
Ember.SimpleAuth.setup(container, application, {
authorizerFactory: 'authorizer:devise'
authorizerFactory: 'ember-simple-auth-authorizer:devise'
});
}
});
```

As token authentication is not actually part of Devise anymore, the server
needs to implement a custom authentication method that uses the provided email
and token to look up the user (see
[discussion here](https://gist.github.com/josevalim/fb706b1e933ef01e4fb6)):

```ruby
class ApplicationController < ActionController::API
before_filter :authenticate_user_from_token!

private

def authenticate_user_from_token!
token = request.headers['auth-token'].to_s
email = request.headers['auth-email'].to_s
return unless token && email

user = User.find_by_email(email)

if user && Devise.secure_compare(user.authentication_token, token)
sign_in user, store: false
end
end
end
```
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ var global = (typeof window !== 'undefined') ? window : {},
see the README and
[discussion here](https://gist.github.com/josevalim/fb706b1e933ef01e4fb6).
_The factory for this authenticator is registered as `'authenticator:devise'`
in Ember's container._
_The factory for this authenticator is registered as
`'ember-simple-auth-authenticator:devise'` in Ember's container._
@class Devise
@namespace Authenticators
Expand All @@ -28,6 +28,15 @@ var Devise = Ember.SimpleAuth.Authenticators.Base.extend({
*/
serverTokenEndpoint: '/users/sign_in',

/**
The devise resource name
@property resourceName
@type String
@default 'user'
*/
resourceName: 'user',

/**
Restores the session from a set of session properties; __will return a
resolving promise when there's a non-empty `auth_token` and a non-empty
Expand Down Expand Up @@ -62,7 +71,8 @@ var Devise = Ember.SimpleAuth.Authenticators.Base.extend({
authenticate: function(credentials) {
var _this = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
var data = {
var data = {};
data[_this.resourceName] = {
email: credentials.identification,
password: credentials.password
};
Expand Down Expand Up @@ -97,11 +107,13 @@ var Devise = Ember.SimpleAuth.Authenticators.Base.extend({
Ember.Logger.warn('Credentials are transmitted via an insecure connection - use HTTPS to keep them secure.');
}
return Ember.$.ajax({
url: this.serverTokenEndpoint,
type: 'POST',
data: data,
dataType: 'json',
contentType: 'application/x-www-form-urlencoded'
url: this.serverTokenEndpoint,
type: 'POST',
data: data,
dataType: 'json',
beforeSend: function(xhr, settings) {
xhr.setRequestHeader('Accept', settings.accepts.json);
}
});
}
});
Expand Down
Loading

0 comments on commit ffb042c

Please sign in to comment.