I am implementing SAML with a web based application and ADFS. The authentication side of thing is working but we now need to pass extra information. The application requires the SAML response in the following format:
<saml:AttributeStatement>
<saml:Attribute Name="mailNickname">
<saml:AttributeValue xsi:type="xs:string">joe.smith182</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="memberOf">
<saml:AttributeValue>CN=SCHOOL.STUDENT.YR9,OU=Groups,OU=Portal,OU=Services,DC=ABC,DC=WIN</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="sn">
<saml:AttributeValue xsi:type="xs:string">Smith</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="givenName">
<saml:AttributeValue xsi:type="xs:string">Joe</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="mail">
<saml:AttributeValue xsi:type="xs:string">joe.smith#mysite.com.au</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="borrowerType">
<saml:AttributeValue xsi:type="xs:string">Student</saml:AttributeValue>
</saml:Attribute>
<saml:AttributeStatement>
What claim rules will we need to setup in ADFS to get this information passed in this format? In particular how can we get the memberOf attribute? I'm not that familiar with claim rule formatting in ADFS so any advice would be appreciated.
If your adding a rule using the claim guide its quite simple. I dont remember how the inteface looks, but when you add a claim, choose the claim rule template: Send LDAP Attributes as Claims.
Then type a name and choose memberships(or something like it) in the LDAP attribute dropdown and type memeberOf in the outgoing claim type.
Then save the rule and you shoudl be good to go
If you want to have a custom attribute name add these two rules
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> add(store = "Active Directory", types = ("memberOf"), query = ";memberOf;{0}", param = c.Value);
c:[Type == "memberOf"]
=> issue(Type = "YOUR_CUSTOM_NAME", Value = c.Value);
Related
Default SOAP Username Token has the following elements:
<wsse:UsernameToken>
<wsse:Username>USERNAME</wsse:Username>
<wsse:Password>PASSWORD</wsse:Password>
</wsse:UsernameToken>
For the same I would to like an additional tokens say Domain & Organization, the schema should look like this,
<wsse:UsernameToken>
<wsse:Username>USERNAME</wsse:Username>
<wsse:Password>PASSWORD</wsse:Password>
<Organization>ORGANIZATION</Organization>
<Domain>DOMAIN</Domain>
</wsse:UsernameToken>
So using Element tag, I appended the elements, here it goes.
wsse = ('wsse', 'http://schemas.xmlsoap.org/ws/2002/12/secext')
security = Element('Security', ns=wsse)
usernametoken = Element('UsernameToken', ns=wsse)
usernametoken.insert(Element('Username', ns=wsse).setText('USERNAME'))
usernametoken.insert(Element('Password', ns=wsse).setText('PASSWORD'))
usernametoken.insert(Element('Organization').setText('ORGANIZATION'))
usernametoken.insert(Element('Domain').setText('DEFAULT'))
security.insert(usernametoken)
Now when I try to set options for the same:
client.set_options(wsse=security)
Am getting the following error:
AttributeError: "wsse" must be: (<class suds.wsse.Security at 0xf552c0>,)
Looks like the type of token class is being changed... Am I missing something
Thanks
Figured it out.
client setting options should be soapheader instead of wsse, here the code goes
client.set_options(soapheaders=security)
I'm trying to invoke ProfileFormHandler's create handle using ATG rest client as shown below.
mSession = RestSession.createSession(mHost, mPort,"kim#example.com","password");
mSession.setUseHttpsForLogin(false);
mSession.login();
Map<String,Object> params = new HashMap<String,Object>();
params.put("value.login", "buddha#oracle.com");
params.put("value.email", "buddha#oracle.com");
params.put("value.password", "password");
RestResult result = RestComponentHelper.executeMethod("/atg/userprofiling/ProfileFormHandler","create",null,params,mSession);
I'm getting form exceptions that says, I'm not passing Login and Password Fields.
["Missing value for the required property Password",
"Missing value for the required property Login name"]
I've tried all combinations of login and password fields like value.login, Login, login, value.Login etc., but nothing seemed to work. All combinations giving the same form exceptions.
How do I invoke an ATG form handler using ATG REST Client and pass parameters to it?
Definitely need more information but looking at your code I can see that you have a value.login which is not configured ootb and believe this is causing the NPE. Assuming you have not customized the ootb ATG RegistrationFormHandler and the required field in the repository the only values you need to pass to the form handler are:
value.email
value.password
value.confirmPassword
value.firstName
value.lastName
Also, the help is specific that the data-type of the value property needs to be java.util.Dictionary
Add the following to /atg/rest/security/restSecurityConfiguration.xml
<resource component="/atg/userprofiling/ProfileFormHandler" secure="false">
<method name="handleCreate" secure="false">
<acl value="EVERYONE:read,write,execute" />
</method>
<property name="value.login" secure="false" />
<property name="value.password" secure="false" />
</resource>
I'm acting as a service provider in a Shibboleth SSO interaction. I'm successfully getting back the SAML response with the expected attributes inside. However, these attributes are not showing up in the /Shibboleth.sso/Session Attributes list.
I have the <MetadataProvider> tag in the shibboleth.xml file. I'm wondering what else I could be doing wrong?
In the shibd.log I see the following:
skipping unmapped SAML 2.0 Attribute with Name: xxxx, Format:urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified
skipping unmapped SAML 2.0 Attribute with Name: yyyy
EDIT - I also added to attribute-map.xml:
<Attribute Name="xxxx" id="xxxx" />
<Attribute Name="yyyy" id="yyyy" />
The attributes do not have fully qualified names in the IdP's metadata.xml. The names are just "xxxx" and "yyyy". Does this matter?
Finally, in the IdP's metadata.xml, they have this:
<saml:Attribute Name="xxxx" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"/>
<saml:Attribute Name="yyyy" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"/>
From Shibboleth documentation:
The SAML V2.0 LDAP/X.500 Attribute Profile specifies that X.500/LDAP
attributes be named by utilizing the urn:oid namespace. These names
are simply constructed using the string urn:oid followed by the OID
defined for the attribute.
So definitely you need to use OID for attribute names, attribute-map.xml has lots of examples.
For custom attributes that are specific to some IdP they will have to supply you with OIDs to use.
I believe I have solved it. In the attribute-map.xml I had to add:
<Attribute name="xxxx" id="xxxx">
<AttributeDecoder xsi:type="NameIDAttributeDecoder" formatter="$Name" defaultQualifiers="true"/>
</Attribute>
<Attribute name="yyyy" id="yyyy">
<AttributeDecoder xsi:type="NameIDAttributeDecoder" formatter="$Name" defaultQualifiers="true"/>
</Attribute>
See here: NativeSPAttributeDecoder
I've created a REST API in an Area of my ASP.NET MVC 4 web application. The API is working properly, and I'd now like to secure it.
Is there a very simple example of how I can do this? I'm going through the samples that came with the DotNetOpenAuth download and I'm completely lost on it.
I had the same problem a couple of days ago. This answer is ridiculously long, maybe there's an easier way.
Personally, I don't use DNOA anymore because it is designed towards self-validating (i.e. encrypted tokens) so you don't need to hit the DB with every request. A very important side effect of this is that an access revocation will not become effective immediately, but only after the token must be renewed. Also, access tokens will become quite long (around 500 bytes).
As a very first step, make sure you know what you need:
OAuth / OAuth2 look easy at first, but it's important to understand how the authorization workflows are designed. Also, their terminology can be irritating, for instance 'Client' refers to what I would naively call client application. It's not the user (who is called 'resource owner' in OAuth terms). My suggestion: Read RFC 6749. It looks dull, but it's an interesting read (and you can skip half of it...)
A key question is: Do you need 2-legged OAuth or 3-legged OAuth (or both?). Which grant types do you need to support?
If you basically want to replace HTTP Basic Auth, the simple "Resource owner password credentials flow" will do. The facebook/twitter kind type of "have this application access my profile information" is 3-legged OAuth.
There's an IBM Documentation that comes with nice grant type diagrams.
Now to DNOA, take a look at Samples/OAuthAuthorizationServer.
A good entry point is the OAuthController.cs file. Note that the Authorize and AuthorizeResponse actions are required only if you want to enable your users to give access to third party applications (3-legged OAuth).
In a 2-legged scenario, users access the OAuth token endpoint directly and simply request an access token. In any case you will need such a controller in your REST application.
The key to the inner workings is the OAuth2AuthorizationServer class (NOT the AuthorizationServer class). Look at Code/OAuth2AuthorizationServer.cs. It implements IAuthorizationServerHost.
Half of that class deals with data storage (which you might want to modify if you're working with a different datastore), and half of it deals with the encryption of the access tokens. You will need to implement IAuthorizationServerHost for your application, too.
Make sure you have a line #define SAMPLESONLY in your code, so it will accept the hardcoded certificate.
To actually authorize the request, it is helpful to write a custom ActionFilterAttribute. Here's some super condensed code, not production ready:
public sealed class BasicAuthenticationAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
private readonly OAuthResourceServer _authServer;
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization.Scheme == "Bearer"
|| actionContext.Request.Properties.ContainsKey("access_token"))
{
authenticatedUser = _authServer.VerifyOAuth2(request, required_claims);
HttpContext.Current.User = authenticatedUser;
Thread.CurrentPrincipal = authenticatedUser;
}
}
}
// See OAuthResourceServer/Code/OAuthAuthorizationManager.cs in DNOA samples
public sealed class OAuthResourceServer
{
public IPrincipal VerifyOAuth2(HttpRequestMessage httpDetails, params string[] requiredScopes)
{
// for this sample where the auth server and resource server are the same site,
// we use the same public/private key.
using (var signing = CreateAuthorizationServerSigningServiceProvider())
{
using (var encrypting = CreateResourceServerEncryptionServiceProvider())
{
var tokenAnalyzer = new StandardAccessTokenAnalyzer(signing, encrypting);
var resourceServer = new ResourceServer(_myUserService, tokenAnalyzer);
return resourceServer.GetPrincipal(httpDetails, requiredScopes);
}
}
}
}
The resource server is still missing
public sealed class MyResourceServer : ResourceServer
{
public override System.Security.Principal.IPrincipal GetPrincipal([System.Runtime.InteropServices.OptionalAttribute]
[System.Runtime.InteropServices.DefaultParameterValueAttribute(null)]
HttpRequestBase httpRequestInfo, params string[] requiredScopes)
{
AccessToken accessToken = this.GetAccessToken(httpRequestInfo, requiredScopes);
string principalUserName = !string.IsNullOrEmpty(accessToken.User)
? this.ResourceOwnerPrincipalPrefix + accessToken.User
: this.ClientPrincipalPrefix + accessToken.ClientIdentifier;
string[] principalScope = accessToken.Scope != null ? accessToken.Scope.ToArray() : new string[0];
// Now your own code that retrieves the user
// based on principalUserName from the DB:
return myUserService.GetUser(userName);
}
}
Next, modify web.config so DNOA doesn't complain about missing SSL connections in development:
<configSections>
<sectionGroup name="dotNetOpenAuth" type="DotNetOpenAuth.Configuration.DotNetOpenAuthSection, DotNetOpenAuth">
<section name="openid" type="DotNetOpenAuth.Configuration.OpenIdElement, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
<section name="oauth" type="DotNetOpenAuth.Configuration.OAuthElement, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
<sectionGroup name="oauth2" type="DotNetOpenAuth.Configuration.OAuth2SectionGroup, DotNetOpenAuth">
<section name="authorizationServer" type="DotNetOpenAuth.Configuration.OAuth2AuthorizationServerSection, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
</sectionGroup>
<section name="messaging" type="DotNetOpenAuth.Configuration.MessagingElement, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
<section name="reporting" type="DotNetOpenAuth.Configuration.ReportingElement, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
</sectionGroup>
</configSections>
<dotNetOpenAuth>
<!-- Allow DotNetOpenAuth to publish usage statistics to library authors to improve the library. -->
<reporting enabled="true" />
<openid>
<provider>
<security requireSsl="false">
</security>
</provider>
</openid>
<oauth2>
<authorizationServer >
</authorizationServer>
</oauth2>
<!-- Relaxing SSL requirements is useful for simple samples, but NOT a good idea in production. -->
<messaging relaxSslRequirements="true">
<untrustedWebRequest>
<whitelistHosts>
<!-- since this is a sample, and will often be used with localhost -->
<add name="localhost"/>
</whitelistHosts>
</untrustedWebRequest>
</messaging>
</dotNetOpenAuth>
I have some working code that I have been using on a test O365 site- it works perfectly. I can authenticate, and pull data using the sharepoint client object model.
On another site, that was migrated from BPOS, claims based auth fails. Specifically, in the SAML token for the working site the structure is like this:
<wst:RequestedSecurityToken>
<wsse:BinarySecurityToken Id="Compact0">bunch of token stuff here</wsse:BinarySecurityToken>
</wst:RequestedSecurityToken>
On the site that does NOT work, this section looks like this:
<wst:RequestedSecurityToken>
<EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" Id="Assertion0" Type="http://www.w3.org/2001/04/xmlenc#Element">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"></EncryptionMethod>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey>
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"></EncryptionMethod>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509SKI>stuff in here</ds:X509SKI>
</ds:X509Data>
<ds:KeyName>microsoftonline.com</ds:KeyName>
</ds:KeyInfo>
<CipherData>
<CipherValue>lots of stuff in here</CipherValue>
</CipherData>
</EncryptedKey>
</ds:KeyInfo>
<CipherData>
<CipherValue>Loads more stuff in here</CipherValue>
</CipherData>
</EncryptedData>
</wst:RequestedSecurityToken>
This is really different! The surrounding areas look pretty much the same as far as I can tell.
What is this telling me? That authentication has failed? The claims auth code I am using is dependent on the 'BinarySecurityToken', so this is why it fails- its not there.
Is there some sharepoint setting I need to tweak? Contact MS support? Anyone?
It's an encrypted response using a KEK (Key Encryption Key). You'll need the public key of the sender to decrypt the EncryptedKey. That lets you use that key to decrypt the CipherData which is what you're after I would think.