OAuth2 (Okta): How to set authorization - authorization

I'm writing an application using Oauth2 using Okta, and I'm running into a problem:
What I would like to do is have Okta (or some other method) to automatically set up and provide authorization details of my user. I already have Okta able to support authentication of the user, I am specifically looking for help regarding authorization. In particular, what I would like to do is divide authorization of my APIs into 3 segments:
1) A group of APIs which are available to any user, even ones who are not authenticated.
2) A group of APIs which are only available to authenticated users.
3) A group of APIs which are locked under permission-based (authorization) requirements.
It's the 3rd group I'm having trouble with. I have my security context set up as follows:
#Configuration
#EnableOAuth2Sso
public class SecurityConfig extends OAuth2SsoDefaultConfiguration {
public SecurityConfig(ApplicationContext applicationContext) {
super(applicationContext);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/anyaccess/**").permitAll()
.antMatchers("/credential/**").hasRole("ADMIN");
super.configure(http);
http.logout().logoutSuccessUrl("/");
}
}
So /anyaccess can be accessed by anyone, and anything else except /credential can be accessed by any authenticated user.
When I log into my application through Okta, I get an Authentication and Principal object which seem to be automatically generated somewhere, somehow (it's this somewhere, somehow that I'm mostly looking for clarification on). However, those objects do not have any set permissions, nor do they appear to provide a way to add additional permissions for future requests. How can I:
1) Set up these Authentication and Principal objects to contain the permissions I want per user?
2) Make sure that these are set up automatically on user sign-in through Okta and don't require an additional API call?
3) Persist changes to this configuration and make that part of my application authorization service?
4) Is there any way I can manage this through Okta configuration, or so I need to have a separate service set up to manage this and tack that onto my Okta authentication service?
Thanks.

You can add user's groups to a "groups" claim and the Okta Spring Boot starter will automatically convert those to Spring Security authorities.
From the top menu, go to API and click on Authorization Servers.
Click on the default authorization server.
Click on the Claims tab.
Click the Add Claim button.
Update the popup form to match the image below.
Note that the Filter Regex is .*.
Then you can use #PreAuthorize("role_name") on your methods.
This blog post has more information.

Related

Keycloak uma-grant type tickets for service accounts do not seem to work with policies

I am trying to use the Keycloak AuthzClient to register resources and related permissions in a resource server.
I have a resource server "resourceserver" with authz service enabled.
Using the AuthzClient, initialized with the json file containing the resource server's client id and secret, I'm able to obtain a pat.
...
authzClient.obtainAccessToken().getToken();
ResourceRepresentation resource = new ResourceRepresentation();
resource.setName("myresource");
resource.setUris(new HashSet<>(Collections.singletonList("urn:resourceserver:resourcetype1:myresource")));
resource.setOwnerManagedAccess(true);
resource.setType("urn:resourceserver:resourcetype1");
resource.addScope("read", "write");
resource = authzClient.protection(pat).resource().create(resource);
UmaPermissionRepresentation permissionRepresentation = new UmaPermissionRepresentation();
permissionRepresentation.setName("myresourcepermissions");
permissionRepresentation.setDescription("foo");
permissionRepresentation.addRole("somerole");
UmaPermissionRepresentation result = authzClient.protection(pat).policy(resource.getId()).create(permissionRepresentation)
After executing this code, I can see, in the keycloak admin UI, that the resource has been created, and the scopes, however the policy/permission don't seem to show up.
I believe it is probably intended, as this keycloak admin UI only shows policies of types client, role, js, etc., but not "uma" which is what UmaPermissionRepresentation creates.
I can however see that policy exists in Keycloak by querying authz/protection/uma-policy with my pat.
So there is something there. Now testing it. I created a regular user and assigned it the realm role somerole. Using this user and some arbitrary public client, I'm able to get an RPT.
First getting an access token using the password grant:
grant_type=password&username=joe&password=password&client_id=somepublicclient
Then exchanging that for an RPT:
grant_type=urn:ietf:params:oauth:grant-type:uma-ticket&audience=resourceserver
The RPT comes back and if I view its contents, I can see the authorization block giving me access to the myresource resource.
However, when I try a similar flow with a service account (to which I also granted the somerole role)using the client credentials flow to obtain the initial access token:
grant_type=client_credentials&client_id=serviceaccount1&client_secret=77c1ffa8-0ea8-420c-ad45-e1a69a03838d
I am able to obtain an RPT, but that RPT does not contain myresource in the authorization/permission block, only the Default resource.
I have been trying to understand why that is. I have also tried using the .addClient("serviceaccount1") or even .addUser("service-account-serviceaccount1") in the UmaPermissionRepresentation, but still, the policy doesn't seem to kick in and my service account does not have access to the resource.
This is using Keycloak 4.8.0.Final.
Note: using the keycloak admin client, I am able to create policies/permissions that actually make this work; but in my environment this would causes other problems because of the roles I would need to assign to the admin client (like viewing all clients to retrieve an id etc.)
I have the same problem with KeyCloak 11.0.2.
Shared resources do not end up in the permission tickets of service accounts. Service accounts are explicitly excluded in the authorization token service.
Since sharing resources with service accounts is possible, this seems inconsistent.
However, you can work around this by explicitly setting the azp claim to something other than your client_id via a protocol mapper on your client.
.

How to authenticate user with just a Google account on Actions on Google?

Currently Google Assitant includes an easy way to request non-identifiable information about the user and a detailed flow to authenticate the user on a third party service through OAuth2. What about if all I need is have the user authenticate on Google itself? I tried filling in the account linking flow using Google OAuth2 information, but that seems not to work. If that last thing is supposed to work fluently than that would be enough of an answer.
Context: Users already authenticate only with Google on a related webpage. All I need is to link this already authenticated account with the less-authenticated account on Google Assistant.
Update, 25 Oct 2018:
As of 13 September 2018, there is now a much simpler way to access the user's account if your project uses Google Sign-In. Google Sign-In for Assistant will give you an ID Token with information about the user, including their Google ID, with their permission. This permission can be granted just using voice and is fairly streamlined.
You can combine this with a web- or app-based Google Sign-In to get their permission to access OAuth scopes if you need to access Google's APIs.
Update, 25 Oct 2017:
As of around 4 Oct or 7 Oct, Google has updated their policy (again) to restore language restricting OAuth endpoints that are valid. The terms now include
When implementing account linking using OAuth, you must own your OAuth endpoint
and it appears (from the comments below) that they now check for the Google endpoints to prevent this method from working.
At this point, the only thing you can do is setup your own OAuth2 server.
Original Post:
Broadly speaking, the auth tasks you need to do are in four parts:
Configure your project (in the cloud console) so that the Calendar API is enabled and that the OAuth2 client is correctly configured.
Configure the Action for account linking in the action console.
Configure the Actions on Google Integration for your API.AI Agent to indicate that sign-in is required.
When API.AI calls your webhook to fulfill an Intent, it will include an auth token as part of the JSON. You can use this token to make calls to the Google APIs you need.
Configure Cloud Project
You need to configure your cloud project so that it has access to the Google APIs you need and setup the OAuth2 Client ID, Secret, and Redirect URI.
Go to https://console.cloud.google.com/apis/dashboard and make sure you have the project you're working with selected. Then make sure you have the APIs you need enabled.
Select the "Credentials" menu on the left. You should see something like this:
Select "Create credentials" and then "OAuth client ID"
Select that this is for a "Web application" (it is... kinda...)
Enter a name. In the screen shot below, I used "Action client" so I remember that this is actually for Actions on Google.
In the "Authorized Redirect URIs" section, you need to include a URI of the form https://oauth-redirect.googleusercontent.com/r/your-project-id replacing the "your-project-id" part with... your project ID in the Cloud Console. At this point, the screen should look something like this:
Click the "Create" button and you'll get a screen with your Client ID and Secret. You can get a copy of these now, but you can also get them later.
Click on "Ok" and you'll be taken back to the "Credentials" screen with the new Client ID added. You can click the pencil icon if you ever need to get the ID and Secret again (or reset the secret if it has been compromised).
Configure the Action Console
Once we have OAuth setup for the project, we need to tell Actions that this is what we'll be using to authenticate and authorize the user.
Go to https://console.actions.google.com/ and select the project you'll be working with.
In the Overview, make your way through any configuration necessary until you can get to Step 4, "Account Linking". This may require you to set names and icons - you can go back later if needed to correct these.
Select the Grant Type of "Authorization Code" and click Next.
In the Client Information section, enter the Client ID and Client Secret from when you created the credentials in the Cloud Console. (If you forget, go to the Cloud Console API Credentials section and click on the pencil.)
For the Authorization URL, enter https://accounts.google.com/o/oauth2/v2/auth
For the Token URL, enter https://www.googleapis.com/oauth2/v4/token
Click Next
You now configure your client for the scopes that you're requesting. Unlike most other places you enter scopes - you need to have one per line. Then click Next.
You need to enter testing instructions. Before you submit your Action, these instructions should contain a test account and password that the review team can use to evaluate it. But you can just put something there while you're testing and then hit the Save button.
Configure API.AI
Over in API.AI, you need to indicate that the user needs to sign-in to use the Action.
Go to https://console.api.ai/ and select the project you're working with.
Select "Integrations" and then "Actions on Google". Turn it on if you haven't already.
Click the "Sign in required for welcome intent" checkbox.
Handle things in your webhook
After all that setup, handling things in your webhook is fairly straightforward! You can get an OAuth Access Token in one of two ways:
If you're using the JavaScript library, calling app.getUser().authToken
If you're looking at the JSON body, it is in originalRequest.data.user.accessToken
You'll use this Access Token to make calls against Google's API endpoints using methods defined elsewhere.
You don't need a Refresh Token - the Assistant should hand you a valid Access Token unless the user has revoked access.
After contacting Google the current situation seems to be that you should set up your own OAuth2 server, and then on the login screen of your OAuth2 server you should start the Google OAuth2 flow.
you have to have your own endpoint with Google Oauth2 - it is correct that you can't use Google Oauth itself as a provider. To use the Google OAuth service, you can use a "sign in with Google" button in your own endpoint instead.
Source: Contacting Google Actions on Google Support
Kind of speechless right now... as this seems to be a huge oversight on Google's part.
I am able to make it work after a long time.
We have to enable the webhook first and we can see how to enable the webhook in the dialog flow fulfillment docs
If we are going to use Google Assistant, then we have to enable the Google Assistant Integration in the integrations first.
Then follow the steps mentioned below for the Account Linking in actions on google:-
Go to google cloud console -> APIsand Services -> Credentials -> OAuth 2.0 client IDs -> Web client -> Note the client ID, client secret from there
-> Download JSON - from json note down the project id, auth_uri, token_uri
-> Authorised Redirect URIs -> White list our app's URL -> in this URL fixed part is https://oauth-redirect.googleusercontent.com/r/ and append the project id in the URL
-> Save the changes
Actions on Google -> Account linking setup
1. Grant type = Authorisation code
2. Client info
1. Fill up client id,client secrtet, auth_uri, token_uri
2. Enter the auth uri as https://www.googleapis.com/auth and token_uri as https://www.googleapis.com/token
3. Save and run
4. It will show an error while running on the google assistant, but dont worry
5. Come back to the account linking section in the assistant settings and enter auth_uri as https://accounts.google.com/o/oauth2/auth
and token_uri as https://accounts.google.com/o/oauth2/token
6. Put the scopes as https://www.googleapis.com/auth/userinfo.profile and https://www.googleapis.com/auth/userinfo.email
and weare good to go.
7. Save the changes.
In the hosting server logs, we can see the access token value and through access token, we can get the details regarding the email address.
Append the access token to this link "https://www.googleapis.com/oauth2/v1/userinfo?access_token=" and we can get the required details in the resulting json page.
accessToken = req.get("originalRequest").get("data").get("user").get("accessToken")
r = requests.get(link)
print("Email Id= " + r.json()["email"])
print("Name= " + r.json()["name"])
You need to implement the Oauth protocol with whatever Google Assistant app you are developing. Let me be a bit more clear:
The user is on the assistant, you need to link him to any data
you have on your App side
The access to the data you have about
your user is protected by an access token
Google then needs to
ask you for this token to have access to this resource
When
google has the token it can send it to the app so it validates every
requests to get the resource.
This is why you need to implement your own oauth server (Honestly it is just two more endpoints in your application): the identity is checked on google's side, but the link between the user and the resource to access can only be known by you.
The process above is valid, you just need to specify your own token endpoint and your own auth endpoint.
Note that if you only want to check that the user is logged in into google and get his email, you just need to implement the streamlined identity flow that does not require the /auth endpoint (Automatically Sign Up Users with Streamlined Identity Flows)
That beeing said I implemented the flow but get the same error :
expected_inputs[0].possible_intents[0]: Transactions/Identity API must be enabled before using.

How to SSO using Rally.RestApi.dll?

Until now, I have read that Rally RestAPI do not support SSO login. I believe this is no longer true as of Jan 2014. The same API is used in Rally Add-in for Excel (here is link for Rally Add-in for Excel) which support SSO login. Can I get either the source code of Rally Excel Add-in or at least someone please provide an example of SSO using Rally RestAPI?
I want to do exactly the same thing what Excel Addin Export functionality does but want to do in pure .net application.
I have added a howto to the C# Rest Api that explains how to do an SSO authentication like Rally does in the Excel plugin. I am pasting it here for convenience.
Thanks, scott
A brief Rally SSO primer
The Rally Web Services API (WSAPI) natively supports only Basic Authentication. Using Basic Authentication, WSAPI sessions must be initiated with a username and password that is validated against a list of usernames and passwords stored directly in Rally. This works fine until clients begin using Single Sign On (SSO). SSO allows clients to use a single enterprise-wide authentication mechanism (like LDAP or Active Directory) to manage user credentials and passwords. Until now, using WSAPI with SSO enabled has required clients to maintain a duplicate user list (the "white" list) in Rally for all users who wish to use the Rally WSAPI. Recent changes to Rally now allow WSAPI users to access Rally using their SSO credentials and alleviate the need to maintain those users in the "white" list.
Note: Rally's current SSO implementation is based on the SAML specification which requires a user to interact with a browser to complete authentication. As such, this technique requires the user to interact with a browser, so it is incompatible with headless WSAPI clients like those that synchronize Rally with VCS and bug tracking tools.
When initiating an SSO connection, the user provides a URL that starts the SSO handshake with Rally's Service Provider (SP), later involving the client's Identity Provider (IdP), and finishes with Rally responding with cookies that represent a valid authenticated session. If that authenticated session cookie is included in any subsequent WSAPI calls, Rally will associate those calls with the authenticated user and the WSAPI calls will be authenticated. To make it easy to get access to the authenticated session cookie for purposes of WSAPI calls following a successful SAML SSO authentication, Rally looks for a parameter added to the initial SSO URL that if present will return a special web page containing the session cookie in clear text as the final product of the SSO handshake. Users can use that data to construct a cookie to be used in subsequent WSAPI calls.
Note: The example URLs below are (potentially) specific to Rally's internal SSO implementation. Since SSO is used to allow customers to provide their own authentication using their own SSO infrastructure (at least the IdP part), SSO URLs will be customer specific. Contact your Rally TAM or Rally Support for help with SSO URLs.
An original SSO URL looks something like:
https://sso.rallydev.com/sp/startSSO.ping?PartnerIdpId=pingidp.f4tech.com-29577
The special parameter is:
TargetResource=https://us1.rallydev.com/slm/j_sso_security_check?noRedirect=true
Note: This name/value pair sets the SSO RelayState in Rally’s specific SSO implementation using PingIdentity as the SSO provider. Other SSO providers may have a different parameter name used to set the RelayState. For instance, some SSO providers use RelayState as the parameter name. In any case, the value is always the same (i.e. “https://us1.rallydev.com/slm/j_sso_security_check?noRedirect=true”)
So a complete URL would look like:
https://sso.rallydev.com/sp/startSSO.ping?PartnerIdpId=pingidp.f4tech.com-29577&TargetResource=https://us1.rallydev.com/slm/j_sso_security_check?noRedirect=true
If a user navigates to this modified SSO URL, after authentication, they will be presented with a web page that contains the following:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>SSO Token</title>
</head>
<body>
<form>
<input type="hidden" name="authCookieName" value="ZSESSIONID"/>
<input type="hidden" name="authCookieValue" value="khkjhkhkhkhkjhh"/>
</form>
</body>
</html>
If the user creates a cookie based on the data contained in this page and passes that cookie along with their subsequent WSAPI calls, those calls will be successfully authenticated. Note that optional cookie data like secure and path must be inferred from call made to obtain the cookie as per the IETF specification for cookies.
So the basic process for logging into Rally from a GUI interface (again, this does not work for headless environments) for the purpose of issuing WSAPI calls is the following:
Collect the SSO URL from the user with the special parameter described above.
Launch a browser pointed to that URL.
After navigating is complete, scrape the cookie values from the returned HTML page.
Close the browser.
Construct a cookie from the cookie values.
Store that cookie for later use.
Send that cookie with all subsequent WSAPI calls.
Repeat this process if the a WSAPI call fails for authentication using this cookie. Remember that these cookies expire and you should be prepared to retry a failed call after re-authentication to create a smooth user experience.
Rally C# ReST API
The Rally C# Rest API has a mechanism integrated into it's connection framework to make this process easy for different GUI clients including automatic re-authentication following session timeout. This includes methods to parse the token page into a valid cookie. Callers of this library can implement other features such as inferring optional cookie data (like domain, path, secure, and host port) to account for situations (like test environments) where Rally does not return complete cookie data.
Connecting to Rally using the C# ReST API means constructing an instance of RallyRestApi. There are two legacy constructors that assume Basic Authentication and take username and password among other parameters. Constructing a RallyRestApi using one of these constructors will always use Basic Authentication and will never use SSO.
A third constructor takes only an IConnectionInfo object. This is the preferred way to obtain a RallyRestApi. Using an IConnectionInfo object to construct a RallyRestApi allows the caller to specify all connection information in one object that can be used for SSO callbacks and authentication sharing between multiple RallyRestApi instances.
IConnectionInfo and ConnectionInfo
To facilitate SSO authentication, the C# ReST API introduced the IConnectionInfo interface and the ConnectionInfo class. These classes represent an object that holds connection preferences and can initiate and complete a browser based SSO authentication session when requested to do so. The ConnectionInfo class implements all of the connection preferences and has methods to parse the Rally SSO landing page into a usable Cookie. This class can be used as is if only Basic Authentication is required. IConnectionInfo is there for flexibility in case the caller does not want to extend or otherwise use ConnectionInfo.
When using IConnectionInfo for Basic Auth simply create a new ConnectionInfo and set the appropriate publicly accessible fields. Use that to construct a RallyRestApi. Any authentication errors will throw exceptions.
Example:
var cInfo = new ConnectionInfo();
cInfo.UserName = "myName";
cInfo.Password = "pass";
cInfo.Server = new Uri("https://host.com");
cInfo.AuthType = Rally.RestApi.AuthorizationType.Basic;
var conn = new RallyRestApi(cInfo);
When using IConnectionInfo for SSO, the caller must implement DoSSOAuth(). Below is an annotated example.
public class MyConnectionInfo : Rally.RestApi.ConnectionInfo
{
public override void doSSOAuth()
{
// Launch a browser to the this.server URI.
// The browser will close automatically if it successfully reaches the SSO landing page
// Users can cancel the SSO handshake
// Abort if the handshake is successful, but didn't arrive at the SSO landing page
var ssoDialog = new SSOAuthDialog(server);
DialogResult result = ssoDialog.ShowDialog();
if (result == DialogResult.Cancel)
throw new Exception("SSO authorization canceled");
else if (result == DialogResult.Abort)
throw new Exception(ssoDialog.abortReason);
// Parse the SSO landing page into a Cookie and save it
AuthCookie = parseSSOLandingPage(ssoDialog.getBrowser().DocumentText);
// Infer Cookie values from SO Landing Page URL if not set
if (String.IsNullOrWhiteSpace(authCookie.Domain) || authCookie.Domain == "null")
authCookie.Domain = ssoDialog.getBrowser().Url.Host;
AuthCookie.Secure = String.Equals(ssoDialog.getBrowser().Url.Scheme,"https",StringComparison.InvariantCultureIgnoreCase);
// Set a specific port port if the SSO Landing Page URL has one
if (!ssoDialog.getBrowser().Url.IsDefaultPort)
Port = ssoDialog.getBrowser().Url.Port;
}
}
This example uses a WinForms dialog with a browser component to present the SSO handshake to the user. Remember, you can use any display technology you want to implement this part. Here is an annotated example:
public partial class SSOAuthDialog : Form
{
public String abortReason;
public SSOAuthDialog(Uri url)
{
InitializeComponent();
webBrowser.Url = url;
}
private void documentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// We have found the SSO Landing Page.
if (webBrowser.DocumentText.Contains("authCookieName") && webBrowser.DocumentText.Contains("authCookieValue"))
{
Trace.TraceInformation("Found SSO authentication token on page: {0}", e.Url.AbsolutePath);
DialogResult = DialogResult.OK;
Close();
}
// We have landed on the Rally ALM page
// This is usually caused by a bad URL
else if (webBrowser.DocumentText.Contains("window.FEATURE_TOGGLES"))
{
abortReason = String.Format("The SSO handshake was successful, but the 'RelayState' was not correctly set. Contact your administrator to obtain the correct URL parameter to set the SSO handshake 'RelayState' to: https://rally1.rallydev.com/slm/j_sso_security_check?noRedirect=true");
Trace.TraceError(abortReason);
DialogResult = DialogResult.Abort;
Close();
}
}
public WebBrowser getBrowser()
{
return webBrowser;
}
}
SSO Example:
var cInfo = new MyConnectionInfo();
cInfo.Server = new Uri("https://host");
cInfo.AuthType = Rally.RestApi.AuthorizationType.SSO;
// This will cause an SSO authentication event
var conn = new RallyRestApi(cInfo);
// This will not b/c it will just use the auth Cookie already in cInfo
var conn2 = new RallyRestApi(cInfo);
When using IConnectionInfo for SSO, it is important to cache the IConnectionInfo object that you send to construct a RallyRestApi. After a successful SSO handshake, the resulting auth Cookie is stored in the IConnectionInfo object and will be used for all subsequent WSAPI calls made from that RallyRestApi object. If you need to create another RallyRestApi object using the same auth Cookie from a previously successful SSO login, simply construct a new RallyRestApi object with the same IConnectionInfo object and if there is an auth Cookie present, it will be used.
Retries
Authorization Cookies can expire. The C# ReST Api will detect an expired SSO Cookie and will initiate a new SSO login session as needed to obtain a new valid Cookie.
That's all there is to it.
SSO is not currently supported by our Toolkits. We use some special hacks to get it working for the Excel plugin but nothing with an interface that is user friendly enough to share with our developer community.
We are working on an OAuth solution that should make projects like this much easier to do. Once it ships we should publish a blog to show you what features it has. My personal hope is that all of our Toolkits will have support to make using OAuth simple.

ASP.NET MVC DotNetOpenAuth authorization server how-to

I have this scenario: a corporate site (MVC 4) and a web shop; add OAuth 2 SSO functionality. Both sites have their own members, but the corp site (for which I'm responsible) must also work as an OAuth 2 authorization server and will store a web shop user id for each member. The shop requested the following endpoints:
Auth endpoint
• authorization:
…/oauth2/authorize?client_id={CLIENT_ID}&state={STATE}&response_type=code&redirect_uri={REDIRECT_URI}
• token
…/oauth2/token?code={TOKEN}&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&redirect_uri={REDIRECT_URI}&grant_type=authorization_code
…/oauth2/token?refresh_token={TOKEN}&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&redirect_uri={REDIRECT_URI}&grant_type=refresh_token
API endpoint
• getid (will return JSON with the shop id of the member):
…/oauth2/api/getid?access_token={TOKEN}
I don't have experience with OAuth, so I was looking at the DotNetOpenAuth samples and have concluded that I need to implement an OAuthAuthorizationServer, but modifying the sample to fit my requirements is difficult as it seems to do more and is complex.
As researching DotNetOpenAuth seems to be so time consuming, I'd like to ask: is modifying the OAuthAuthorizationServer sample the right approach? Or should I try to make a native implementation or try a different OAuth library that may be easier to use in my situation?
Please comment on my overall plan:
-keep the corp site member login flow standard forms auth, straightforward LogOn controller
-add an OAuth controller that will implement the three required endpoints as actions
-when the authorization action is reached, I validate the client and redirect to LogOn passing on the redirect_uri; I think the Authorize ActionResult from OAuthController.cs from the sample is where I should start investigating this, and return an AccountAuthorizeModel. Is this correct?
-after the user logs in, and if the login page was reached from the authorization endpoint, I redirect to redirect_uri with the code attached; I don't know where to start with this one. PrepareApproveAuthorizationRequest then PrepareResponse? Where does the code come from? Where in the flow should I add a new ClientAuthorization in the database?
-the shop will then use the code to get or refresh the token, from the /token endpoint; simply return HandleTokenRequest?
-with the token the shop site will be able to get the member data JSON; have to find out how to validate the token
Now, besides adding a Clients table to store the client ids and secrets, and ClientAuthorization to keep track of who's authorized, I don't know if the other tables from the DotNetOpenAuth sample are used and when: Nonce, SymmetricCryptoKey, User.
Modifying OAuth2AuthorizationServer.cs seems straightforward, I only have to add real certificates and make sure the clients are pulled from my data context.
Thanks!
I think you are right in most of the points. Let's comment them:
OAuth server should have 2 endpoints (not 3), as requesting token and refreshing token goes to the same endpoint (TokenEndpoint).
It depends if your are going to implement a different authentication server (or controller), or you are going to implement the authentication responsibility inside the authorization server. In case they are separated, the authentication server should be the one responsible of displaying the logon, authenticate and communicate with authorization server using OpenID protocol (Also supported by DotNetOpenAuth).
Once the user is authenticated, the authorization server should store the data of the user identity somehow, and return the authorization code (if using this Oauth flow) using DotNetOpenAuth functions:
var response =
this.AuthServer.PrepareApproveAuthorizationRequest(AuthorizationRequest,
User.Identity.Name);
return this.AuthServer.Channel.PrepareResponse(response);
finalResponse.AsActionResult();
I don't think you need to save nothing about the authorization process in the database, and the code is generated by DotNetOpenAuth and sent to the client into the query string of the redirection.
Then, the client should get the code (ProcessUserAuthorization) and call the TokenEndpoint. This endpoint is just returning HandleTokenRequest, that internally is calling to some OAuthAuthorizationServer functions, such as CreateAccessToken.
Once the client has the access token, it should call the resources, sending the token into the HTTP Header 'Authorization'. The resource server is the responsible to validate the token.
var resourceServer = new ResourceServer(new
StandardAccessTokenAnalyzer(signing, encrypting));
AccessToken token = resourceServer.GetAccessToken(request, scopes);
A store provider for nonce and crytoKeys is needed using this flow. Have a look to class InMemoryCryptoKeyStore in:
https://github.com/DotNetOpenAuth/DotNetOpenAuth/wiki/Security-scenarios
Hope this helps!

CAS authentication and limiting access for specified users

I'm using CAS (Central Authentication Service) from Jasig in a client JSF app running on tomcat 6 server. I would like to limit the access to the app just for the users specified in my database rather than all the users which can be authenticated using that CAS service. When the user attempts to log in, I need to check if his username is also in my database's table user and if it is - allow the access to the app. Otherwise, I would like to redirect user to a page "You don't have permission to access this part of the application". So I need authorization as well. Is there a good way to authorize the users in jsf 2.0? Thanks in advance for any help/suggestions.
Sounds like you need to design a custom Authentication Handler class in CAS. In theory, your handler would extend this [1], perform all the necessary checks and database look ups and will then be able to return a signal that indicates whether or not the user could authN.
You should then reference your custom handler in the deploerConfigContext.xml file.
For displaying the message, you could either throw an exception with the proper messages code, such that the message would appear above the login form, or you could alter the spring webflow and generate a new view-state which the user would be redirected to, if they fail to get access. The first approach is much easier to implement.
Another approach would be to take advantage of the isUserInRole() method [2] using the persondir api.
[1] http://developer.jasig.org/projects/cas/cas-server-core/cas-server/cas-server-core/apidocs/org/jasig/cas/authentication/handler/support/AbstractUsernamePasswordAuthenticationHandler.html
[2] https://wiki.jasig.org/pages/viewpage.action?pageId=47874068