LiveCycle supports various web service authentication
modes when invoking services. One authentication mode is specifying
both a user name and password value using a basic authorization
header in the web service call. LiveCycle also supports
SAML assertion-based authentication. When a client application invokes
a LiveCycle service using a web service, the client application
can provide authentication information in one of the following ways:
-
Passing credentials as part of Basic Authorization
-
Passing username token as part of WS-Security header
-
Passing a SAML assertion as part of WS-Security header
-
Passing Kerberos token as part of WS-Security header
LiveCycle does not support standard certificate-based
authentication but it does support certificate-based authentication
in a different form.
Note:
The web service quick starts in Programming
with LiveCycle specify user name and password values to
perform authorization.
The identity of AEM forms users can be represented through
a SAML assertion signed using a secret key. The following XML code
shows an example of a SAML assertion.
<Assertion xmlns="urn:oasis:names:tc:SAML:1.0:assertion"
xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"
xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"
AssertionID="fd4bd0c87302780e0d9bbfa8726d5bc0" IssueInstant="2008-04-17T13:47:00.720Z" Issuer="LiveCycle"
MajorVersion="1" MinorVersion="1">
<Conditions NotBefore="2008-04-17T13:47:00.720Z" NotOnOrAfter="2008-04-17T15:47:00.720Z">
</Conditions>
<AuthenticationStatement
AuthenticationInstant="2008-04-17T13:47:00.720Z"
AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:unspecified">
<Subject>
<NameIdentifier NameQualifier="DefaultDom">administrator</NameIdentifier>
<SubjectConfirmation>
<ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</ConfirmationMethod>
</SubjectConfirmation>
</Subject>
</AuthenticationStatement>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"></ds:SignatureMethod>
<ds:Reference URI="#fd4bd0c87302780e0d9bbfa8726d5bc0">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"
PrefixList="code ds kind rw saml samlp typens #default">
</ec:InclusiveNamespaces>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>hVrtqjWr+VzaVUIpQx0YI9lIjaY=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>UMbBb+cUcPtcWDCIhXes4n4FxfU=</ds:SignatureValue>
</ds:Signature>
</Assertion>
This example assertion is issued for an administrator user. This
assertion contains the following noticeable items:
-
It is valid for certain duration.
-
It is issued for a particular user.
-
It is digitally signed. So any modification done to it would
break the signature.
-
It can be presented to LiveCycle as a token of user's
identity similar to user name and password.
A client application can retrieve the assertion from any LiveCycle AuthenticationManager API which returns an
AuthResult
object.
You can obtain an
AuthResult
instance by performing
one of the following two methods:
-
Authenticating the user using any of the authenticate
methods exposed by AuthenticationManager API. Typically, one would
use the user name and password; however, you can also use the certificate
authentication.
-
Using the
AuthenticationManager.getAuthResultOnBehalfOfUser
method.
This method lets a client application get an
AuthResult
object
for any AEM forms user.
a AEM forms user can be authenticated using a SAML token
that is obtained. This SAML assertion (xml fragment) can be send
as part of the WS-Security header with the web service call for
user authentication. Typically, a client application has authenticated
a user but has not stored the user credentials. (Or the user has
logged on to that client through a mechanism other than using a
user name and password.) In this situation, the client application
has to invoke LiveCycle and impersonate a specific user
which is allowed to invoke LiveCycle.
To impersonate a specific user, invoke the
AuthenticationManager.getAuthResultOnBehalfOfUser
method using
a web service. This method returns an
AuthResult
instance
which contains the SAML assertion for that user.
Next, use that SAML assertion to invoke any service that requires
authentication. This action involves sending the assertion as part
of the SOAP header. When a web service call is made with this assertion,
LiveCycle identifies the user as the one represented by
that assertion. That is, the user specified in the assertion is
the user who is invoking the service.
Using Apache Axis classes and SAML-based authentication
You can invoke a LiveCycle service by Java proxy
classes that were created using the Axis library. (See
Creating Java proxy classes using Apache Axis
.)
When using AXIS that uses SAML-based authentication, register
the request and response handler with Axis. Apache Axis invokes
the handler before sending an invocation request to LiveCycle.
To register a handler, create a Java class that extends
org.apache.axis.handlers.BasicHandler
.
Create an AssertionHandler with Axis
The following Java class,
named
AssertionHandler.java
, shows an example of
a Java class that extends
org.apache.axis.handlers.BasicHandler
.
public class AssertionHandler extends BasicHandler {
public void invoke(MessageContext ctx) throws AxisFault {
String assertion = (String) ctx.getProperty(LC_ASSERTION);
//no assertion hence nothing to insert
if(assertion == null) return;
try {
MessageElement samlElement = new MessageElement(convertToXML(assertion));
SOAPHeader header = (SOAPHeader) ctx.getRequestMessage().getSOAPHeader();
//Create the wsse:Security element which would contain the SAML element
SOAPElement wsseHeader = header.addChildElement("Security", "wsse", WSSE_NS);
wsseHeader.appendChild(samlElement);
//remove the actor attribute as in LC we do not specify any actor. This would not remove the actor attribute though
//it would only remove it from the soapenv namespace
wsseHeader.getAttributes().removeNamedItem("actor");
} catch (SOAPException e) {
throw new AxisFault("Error occured while adding the assertion to the SOAP Header",e);
}
}
}
Register the handler
To register a handler with Axis, create a
client-config.wsdd file. By default, Axis looks for a file with
this name. The following XML code is an example of a client-config.wsdd
file. See Axis documentation for more information.
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<transport name="http" pivot="java:org.apache.axis.transport.http.HTTPSender"/>
<globalConfiguration >
<requestFlow >
<handler type="java:com.adobe.idp.um.example.AssertionHandler" />
</requestFlow >
</globalConfiguration >
</deployment>
Invoke a LiveCycle service
The following code example
invokes a LiveCycle service using SAML-based authentication.
public class ImpersonationExample {
. . .
public void authenticateOnBehalf(String superUsername,String password,
String canonicalName,String domainName) throws UMException, RemoteException{
((org.apache.axis.client.Stub) authenticationManager).setUsername(superUsername);
((org.apache.axis.client.Stub) authenticationManager).setPassword(password);
//Step 1 - Invoke the Auth manager api to get an assertion for the user to be impersonated
AuthResult ar = authenticationManager.getAuthResultOnBehalfOfUser(canonicalName, domainName, null);
String assertion = ar.getAssertion();
//Step 2 - Setting the assertion here to be picked later by the AssertionHandler. Note that stubs are not threadSafe
//hence should not be reused. For this simple example we have made them instance variable but care should be taken
//regarding the thread safety
((javax.xml.rpc.Stub) authorizationManager)._setProperty(AssertionHandler.LC_ASSERTION, assertion);
}
public Role findRole(String roleId) throws UMException, RemoteException{
//This api would be invoked under bob's user rights
return authorizationManager.findRole(roleId);
}
public static void main(String[] args) throws Exception {
ImpersonationExample ie = new ImpersonationExample("http://localhost:5555");
//Get the SAML assertion for the user to impersonate and store it in stub
ie.authenticateOnBehalf(
"administrator", //The Super user which has the required impersonation permission
"password", // Password of the super user as referred above
"bob", //Cannonical name of the user to impersonate
"testdomain" //Domain of the user to impersonate
);
Role r = ie.findRole("BASIC_ROLE_ADMINISTRATOR");
System.out.println("Role "+r.getName());
}
}
Using a .NET client assembly and SAML-based authentication
You can invoke a LiveCycle service by using a .NET
client assembly and SAML-based authentication. To do so, you must
use the Web Service Enhancements 3.0 (WSE). For information about
creating a .NET client assembly that uses WSE, see
Creating a .NET project that uses DIME
.
Note:
The DIME section uses WSE 2.0. To use SAML-based
authentication, follow the same instructions that are specified
in the DIME topic. However, replace WSE 2.0 with WSE 3.0. Install
Web Services Enhancements 3.0 on your development computer and integrate
it with Microsoft Visual Studio .NET. You can download Web Services Enhancements
3.0 from the
Microsoft Download Center
.
The WSE architecture uses Policies, Assertions, and SecurityToken
data types. Briefly, for a web service call, specify a policy. A
policy can have multiple assertions. Each assertion can contain
filters. A filter is invoked at certain stages in a web service
call and, at that time, they can modify the SOAP request. For full details,
see the Web Service Enhancements 3.0 documentation.
Create the Assertion and Filter
The following C# code example
creates filter and assertion classes. This code example creates
a SamlAssertionOutputFilter. This filter is invoked by the WSE framework
before the SOAP request is sent to LiveCycle.
class LCSamlPolicyAssertion : Microsoft.Web.ServicES4.Design.PolicyAssertion
{
public override Microsoft.Web.ServicES4.SoapFilter CreateClientOutputFilter(FilterCreationContext context)
{
return new SamlAssertionOutputFilter();
}
. . .
}
class SamlAssertionOutputFilter : SendSecurityFilter
{
public override void SecureMessage(SoapEnvelope envelope, Security security)
{
// Get the SamlToken from the SessionState
SamlToken samlToken = envelope.Context.Credentials.UltimateReceiver.GetClientToken<SamlToken>();
security.Tokens.Add(samlToken);
}
}
Create the SAML Token
Create a class to represent the SAML assertion.
The main task that this class performs is convert data values from
string to xml and preserve white space. This assertion xml is later
imported into the SOAP request.
class SamlToken : SecurityToken
{
public const string SAMLAssertion = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1";
private XmlElement _assertionElement;
public SamlToken(string assertion)
: base(SAMLAssertion)
{
XmlDocument xmlDoc = new XmlDocument();
//The white space has to be preserved else the digital signature would get broken
xmlDoc.PreserveWhitespace = true;
xmlDoc.LoadXml(assertion);
_assertionElement = xmlDoc.DocumentElement;
}
public override XmlElement GetXml(XmlDocument document)
{
return (XmlElement)document.ImportNode(_assertionElement, true);
}
. . .
}
Invoke a LiveCycle service
The following C# code example
invokes a LiveCycle service by using SAML-based authentication.
public class ImpersonationExample
{
. . .
public void AuthenticateOnBehalf(string superUsername, string password, string canonicalName, string domainName)
{
//Create a policy for UsernamePassword Token
Policy usernamePasswordPolicy = new Policy();
usernamePasswordPolicy.Assertions.Add(new UsernameOverTransportAssertion());
UsernameToken token = new UsernameToken(superUsername, password, PasswordOption.SendPlainText);
authenticationManager.SetClientCredential(token);
authenticationManager.SetPolicy(usernamePasswordPolicy);
//Get the SAML assertion for impersonated user
AuthClient.AuthenticationManagerService.AuthResult ar
= authenticationManager.getAuthResultOnBehalfOfUser(canonicalName, domainName, null);
System.Console.WriteLine("Received assertion " + ar.assertion);
//Create a policy for inserting SAML assertion
Policy samlPolicy = new Policy();
samlPolicy.Assertions.Add(new LCSamlPolicyAssertion());
authorizationManager.SetPolicy(samlPolicy);
//Set the SAML assertion obtained previously as the token
authorizationManager.SetClientCredential(new SamlToken(ar.assertion));
}
public Role findRole(string roleId)
{
return authorizationManager.findRole(roleId);
}
static void Main(string[] args)
{
ImpersonationExample ie = new ImpersonationExample("http://localhost:5555");
ie.AuthenticateOnBehalf(
"administrator", //The Super user which has the required impersonation permission
"password", // Password of the super user as referred above
"bob", //Cannonical name of the user to impersonate
"testdomain" //Domain of the user to impersonate
);
Role r = ie.findRole("BASIC_ROLE_ADMINISTRATOR");
System.Console.WriteLine("Role "+r.name);
}
}
|
|
|