Skip to content

Commit

Permalink
Added docs for login flows for user and client. Added protected confi…
Browse files Browse the repository at this point in the history
…rm page in the OauthController. Added BootStrap to test interaction with provider and client.

Fixed bug with filter position not being loaded correctly on startup.
  • Loading branch information
bluesliverx committed Oct 6, 2011
1 parent 434cf9b commit 4d9277d
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 6 deletions.
67 changes: 66 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
This plugin is an OAuth2 Provider based on the spring security libraries. It is based off of Burt Beckwith's OAuth Provider plugin (never officially released).

NOTE: This plugin is incomplete still and does not provide full functionality. The full flow of logging in with both users and clients work, but there
still remains no way for the resources to be protected in a manner matching that of the Spring Security Core 'Secured' annotations.

## How to Use

### OAuth Controller/View

The `user.confirmUrl` setting controls where the user will be redirected to confirm access to a certain client

### Register Clients

This is an example of registering a client (to be run in the BootStrap of your application):
Expand All @@ -24,6 +31,64 @@ class BootStrap {
}
```

## Login Flows

### Client Login

The client may login with the URL given in the `client.authUrl` setting (`/oauth/authorize` by default) by using the following syntax.
Notice the `grant_type` of `client_credentials` and that the client credentials from the example above are used.

```
http:https://localhost:8080/app/oauth/authorize?grant_type=client_credentials&response_type=code&client_id=clientId&client_secret=clientSecret
```

The response from a login such as this is the following JSON. The `access_token` is the important piece here.

```javascript
{
"access_token": "449acfe6-663f-4fde-b1f8-414c867a4cb5",
"expires_in": 43200,
"refresh_token": "ab12ce7a-de9d-48db-a674-0044897074b0"
}
```

### User Approval of Clients

The following URLs or configuration options show a typical flow authorizing a client for a certain user.

* The client must first be logged in using the URL above.
* Separately, the client must be logged into the application protected by OAuth. Alternatively, they will be logged in
on the next step since the `user.confirmUrl` is protected or *should* be protected with a Spring Security Core `Secured`
annotation.
* A user attempting to use a service provided by the OAuth protected application through the client reaches the client. The
client then redirects the user to the `user.authUrl` setting (`/oauth/user/authorize` by default). This will actually
redirect the user to the `user.confirmUrl` setting which will present the user with an option to authorize or deny access
to the client to the application.

```
http:https://localhost:8080/app/oauth/user/authorize?response_type=code&client_id=clientId&redirect_uri=http:https://localhost:8080/app/
```

The user will then be redirected to the `redirect_uri` with the code appended as a URL parameter such as:

```
http:https://localhost:8080/app/?code=YjZOa8
```

* The client captures this code and sends it to the application at the `client.authUrl` setting.
This will allow the client to access the application as the user. Notice the `grant_type` of `authorization_code` this time.

```
http:https://localhost:8080/app/oauth/authorize?grant_type=authorization_code&client_id=clientId&code=OVD8SZ&redirect_uri=http:https://localhost:8080/app/
```

This will then give a token to the client that can be used to access the application as the user (an example needs to go here).

### Protecting Resources

This section of the plugin still needs work to tie in the Spring Security Core `Secured` annotation or intercept URL map or Request Map definitions
with the OAuth provider concept of protected resources.

## Configuration

### URLs
Expand All @@ -33,7 +98,7 @@ By default, URLs have been defined. Their default values and how they would be
```groovy
grails.plugins.springsecurity.oauthProvider.user.authUrl = "/oauth/user/authorize" // Where the user is authorized
grails.plugins.springsecurity.oauthProvider.client.authUrl = "/oauth/authorize" // Where the client is authorized
grails.plugins.springsecurity.oauthProvider.user.confirmUrl = "/login/confirm" // Where the user confirms that they approve the client
grails.plugins.springsecurity.oauthProvider.user.confirmUrl = "/oauth/confirm" // Where the user confirms that they approve the client
```

### Custom Beans
Expand Down
8 changes: 4 additions & 4 deletions SpringSecurityOauth2ProviderGrailsPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ OAuth2 Provider support for the Spring Security plugin. Based on Burt Beckwith\
SpringSecurityUtils.registerProvider 'oauthClientPasswordAuthenticationProvider'
SpringSecurityUtils.registerProvider 'oauthClientCredentialsAuthenticationProvider'
SpringSecurityUtils.registerFilter 'oauthExceptionHandlerFilter',
conf.filterStartPosition + 1
conf.oauthProvider.filterStartPosition + 1
SpringSecurityUtils.registerFilter 'verificationCodeFilter',
conf.filterStartPosition + 2
conf.oauthProvider.filterStartPosition + 2
SpringSecurityUtils.registerFilter 'oauthAuthorizationFilter',
conf.filterStartPosition + 3
conf.oauthProvider.filterStartPosition + 3
SpringSecurityUtils.registerFilter 'oauthProtectedResourceFilter',
conf.filterStartPosition + 4
conf.oauthProvider.filterStartPosition + 4
SpringSecurityUtils.registerFilter 'oauthUserApprovalFilter', 1

// Providers
Expand Down
20 changes: 20 additions & 0 deletions grails-app/conf/BootStrap.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import org.springframework.security.oauth2.provider.BaseClientDetails;
import grails.util.Environment;

class BootStrap {
def grailsApplication
def clientDetailsService

def init = { servletContext ->
// Add client to oauth provider
def client = new BaseClientDetails()
client.clientId = "clientId"
client.clientSecret = "clientSecret"
client.authorizedGrantTypes = ["authorization_code", "refresh_token", "client_credentials"]
clientDetailsService.clientDetailsStore = [
"clientId":client
]
}
def destroy = {
}
}
2 changes: 1 addition & 1 deletion grails-app/conf/DefaultOAuth2ProviderSecurityConfig.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ security {
approvalParameter = "user_oauth_approval"
approvalParameterValue = true
authUrl = '/oauth/user/authorize'
confirmUrl = '/login/confirm'
confirmUrl = '/oauth/confirm'
}
client {
authUrl = '/oauth/authorize'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package grails.plugins.springsecurity.oauthProvider

import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
import grails.plugins.springsecurity.Secured

class OauthController {
def verificationCodeFilter
def clientDetailsService

/**
* Show the confirm page
*/
@Secured(["IS_AUTHENTICATED_REMEMBERED"])
def confirm = {
def config = SpringSecurityUtils.securityConfig
def clientAuth = verificationCodeFilter.authenticationCache.getAuthentication(request, response)

String postUrl = "${request.contextPath}${config.oauthProvider.user.authUrl}"
[postUrl: postUrl, approvalParameter: config.oauthProvider.user.approvalParameter,
approvalParameterValue: config.oauthProvider.user.approvalParameterValue,
client:clientDetailsService.loadClientByClientId(clientAuth.getClientId())]
}
}
67 changes: 67 additions & 0 deletions grails-app/views/oauth/confirm.gsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<head>
<meta name='layout' content='main' />
<title>Login</title>
<style type='text/css' media='screen'>
#login {
margin:15px 0px; padding:0px;
text-align:center;
}
#login .inner {
width:260px;
margin:0px auto;
text-align:left;
padding:10px;
border-top:1px dashed #499ede;
border-bottom:1px dashed #499ede;
background-color:#EEF;
}
#login .inner .fheader {
padding:4px;margin:3px 0px 3px 0;color:#2e3741;font-size:14px;font-weight:bold;
}
#login .inner .cssform p {
clear: left;
margin: 0;
padding: 5px 0 8px 0;
padding-left: 105px;
border-top: 1px dashed gray;
margin-bottom: 10px;
height: 1%;
}
#login .inner .cssform input[type='text'] {
width: 120px;
}
#login .inner .cssform label {
font-weight: bold;
float: left;
margin-left: -105px;
width: 100px;
}
#login .inner .login_message {color:red;}
#login .inner .text_ {width:120px;}
#login .inner .chk {height:12px;}
</style>
</head>

<body>
<div id='login'>
<div class='inner'>
<g:if test='${flash.message}'>
<div class='login_message'>${flash.message}</div>
</g:if>
<div class='fheader'>Please Confirm</div>
<div>You hereby authorize <b>${client.clientId}</b> to access your protected resources.</div>
<form action='${postUrl}' method='POST' id='confirmationForm' class='cssform'>
<p>
<input name='${approvalParameter}' type='hidden' value='${approvalParameterValue}' />
<label><input name="authorize" value="Authorize" type="submit" /></label>
</p>
</form>
<form action='${postUrl}' method='POST' id='denialForm' class='cssform'>
<p>
<input name='${approvalParameter}' type='hidden' value='not_${approvalParameterValue}' />
<label><input name="deny" value="Deny" type="submit" /></label>
</p>
</form>
</div>
</div>
</body>

0 comments on commit 4d9277d

Please sign in to comment.