09 May 2017

1. Credentials

The <Credentials> element contains the following attributes:

containerManaged

A boolean value. Specifies if authentication is carried out via the servlet container. See chapter below how to configure this.

runAs

A string value. Defines the name of the ENOVIA/3DExperience user that we will run the service as.

runAsSuperUser

A boolean value. Useful together when containerManaged=true and you want to run the service as a super-user, while authentication is required.

handler

The fqn name of a class that implements the interface com.technia.tif.enovia.security.ContextProviderHandler. See further down in this document for more details.

Valid child elements are defined in the table below

Element Description Mandatory

<SecurityContext>

Used for defining the ENOVIA/3DExperience security context.

See below how to configure this.

No

<Role>

In case container managed authentication is enabled, you may define additional roles, which the authenticated user must have in order to gain access. These roles are typically not ENOVIA/3DExperience roles, in case of Kerberos authentication these will be roles from your Active Directory.

Note that if you specify multiple roles, the user is only required to have one of the listed roles in order to get access. Example below:

<Credentials containerManaged="true" ...>
    <Role name="name-of-role1" />
    <Role name="name-of-role2" />
    ...
</Credentials>

No.

<Assignments>

Specify additional ENOVIA/3DExperience assignments the user must have in order to proceed. Example below:

<Credentials ...>
    <Assignments>
        <Role name="Desing Engineer" />
        <Role name="Another Role" />
    </Assignments>
    ...
</Credentials>

No

1.1. Custom Context Provider Handler

In some cases you may need some more fine-tuned control over what ENOVIA/3DExperience Context to be used.

The handler attribute is used to point out the class implementing the interface com.technia.tif.enovia.security.ContextProviderHandler.

If you have enabled container managed authentication, the servlet container (the Jetty engine) have already done some authentication. In case you are using "enovia" as the login-service you will in that case has a "Context" set already. This Context Provider Handler cannot override/by-pass the container managed logic - if this is needed then you should disable the container managed security and take care about this in your custom ContextProviderHandler.
public class MyContextProviderHandler implements ContextProviderHandler {

    @Override
    public ContextProvider apply(AuthorizationContext ctx, CredentialsConfig config) {
        // Principal available in case container-managed-security is enabled. Otherwise, null.
        Principal p = ctx.getPrincipal();

        // EXAMPLE: Use the ENOVIA user credentials directly.
        if (principal instanceof EnoviaUserPrincipal) {
            EnoviaUserPrincipal eup = (EnoviaUserPrincipal) principal;
            if (eup.isValid()) {
                return eup;
            }
        }

        // EXAMPLE: Get headers
        List<String> headerNames = ctx.getHeaderNames();
        for (String header : headerNames) {
            System.out.printf("Header>>> %30s : %s%n", header, ctx.getHeaderValues(header));
        }

        // EXAMPLE: Get parameters
        List<String> paramNames = ctx.getParameterNames();
        for (String param : paramNames) {
            System.out.printf("Parameter>>> %30s : %s%n", param,
                    StringUtils.concat(ctx.getParameterValues(param), "|"));
        }

        // EXAMPLE: Get other request based properties
        if (ctx instanceof RequestBasedAuthorizationContext) {
            RequestBasedAuthorizationContext rctx = (RequestBasedAuthorizationContext) ctx;
            System.out.printf("Request URI>> %s%n", rctx.getHttpServletRequest().getRequestURI());
        }

        // EXAMPLE: Run as specific user
        String runAs = ctx.getHeaderValue("x-run-as");
        return ContextProviders.getRunAs(runAs);
    }
}
In the above example we are not considering if the Credentials have been configured with Security Context nor Authorization rules. If you want to do this you can see below how to do so.
import com.technia.tif.enovia.security.DefaultContextProviderHandler;

...
ContextProvider contextProvider = ...;
return DfaultContextProviderHandler.getInstance().apply(ctx, credentials, contextProvider);

1.2. Security Context

Via the <SecurityContext> element you define what security context to use. You may do the following.

  1. Point out a mapping file

    1. Or use a default mapping file

  2. Specify a named security context

  3. Or use the "default" security context as configured for the ENOVIA/3DExperience user

To point out a mapFile use the syntax below.

The file is relative to ${TIF_ROOT}/modules/enovia/etc
<SecurityContext mapFile="sec-mapping.xml" />

Use the default mapping file. The default file is specified via the property securityMapping.defaultFile, and the default value is security-context-mapping.xml.

The file is relative to ${TIF_ROOT}/modules/enovia/etc
<SecurityContext useDefaultMapFile="true" />

The format of the mapping file is shown below:

<Contexts>
    <Context name="Design Engineer.Company Name.GLOBAL">
        <User is="user1" />(1)
        <User is="user2" />
        <User is="user3" />

        <Role is="engineer" /> (2)
        <Role is="designer" />

        <Parameter name="test" is="something" /> (3)
        <Parameter name="x" is="y" />
    </Context>
    <Context name="...">...</Context>
    <Context name="...">...</Context>
</Contexts>

NOTE that specifying user and role requires having enabled container managed authentication (Kerberos or Basic Authenticaton etc.)

1 Specifies certain users to match against
2 Specifies additional roles the user should have
3 Specifies additional parameters and value to be evaluated In case of a REST service, the parameters are the request parameters passed to the service.

The evaluation logic is:

  1. User list is EMPTY or user is in list

  2. Role list is EMPTY or user have one of the roles in the list

  3. Parameter list is EMPTY or one of the parameters have the expected value

If A AND B AND C is satisfied, then use the security context defined for this "rule".

To use a specific Security Context:

<SecurityContext use="Design Engineer.Company Name.GLOBAL" />

Specify using the default security context.

<SecurityContext useDefault="true" />

1.3. Container Managed Security

You can enable security on the servlet container level and either use Kerberos/SPNego authentication OR use Basic authentication and authenticate against the ENOVIA/3DExperience database.

1.4. Configure Security Realm

Within the ${TIF_ROOT}/modules/enovia/etc/module.custom.properties, you need to specify what login service to be used including its realm and optionally some extra parameters.

The login services currently supported are

app-token

A login service that will authenticate the remote user against the Tokens declared from the administration UI.

enovia

A login service that will authenticate the remote user against the ENOVIA/3DExperience database.

ldap

A login service that will authenticate the remote user against a LDAP directory (for example Active Directory)

spnego

A login service supporting Single Sign On against Active Directory.

In order to use Spnego authentication, also read this document in order to set up the core parts of Spnego/Kerberos.

1.4.1. LDAP Authentication

If the "loginService" is set to "ldap", TIF will authenticate users against a LDAP directory.

http.webapp.app-id.loginService=ldap
http.webapp.app-id.realm=Webservices

The second value defines the "realm". (See https://www.ietf.org/rfc/rfc2617.txt for more information about realms and basic authentication).

There are some additional LDAP settings required to be defined. You can specify global LDAP parameters and/or web application specific LDAP parameters. In most cases you will be fine with only global LDAP settings.

For convenience, the application specific parameters will be merged with the global LDAP parameters. Hence, you only need to override/define the parameters that is different on the application level.

Please see the table below.

The global parameter name is ldap., while the application specific parameter are named like http.webapp.<APP_NAME>.ldap.
Parameter Description Required

ldap.server

Defines the server or list of LDAP servers.

Separate with space if using multiple.

Yes

ldap.rootDN

Defines the root dn, where all LDAP searches starts from.

If we can start a search starting at a sub-node (as opposed to root), you get a better performance because it narrows down the scope of a search. This field specifies the DN of such a subtree.

No

ldap.userSearchBase

The relative DN (From the root DN) that further narrow down searches to the sub-tree.

If you do specify this value, the field normally looks something like "ou=people".

No

ldap.userSearchFilter

This field determines the query to be run to identify the user record. The query is almost always "uid={0}" as per defined in RFC 2798, so in most cases you should leave this field empty and let this default kick in.

If your LDAP server doesn’t have uid or doesn’t use a meaningful uid value, try "mail={0}", which lets people login by their e-mail address.

If you do specify a different query, specify an LDAP query string with marker token "{0}", which is to be replaced by the username string entered by the user.

Yes

ldap.groupMembershipAttribute

If the user entry in the LDAP tree contains an attribute with the group membership, then specify that attribute here.

Otherwise, we need to query for the groups a user belongs to.

Either this or the groupSearchBase / groupSearchFilter needs to be defined.

ldap.groupSearchBase

This field determines the query to be run to identify the organizational unit that contains groups. The query is almost always "ou=groups" so try that first, though this field may be left blank to search from the root DN.

Not needed, but if the groupMembershipAttribute is undefined you can use this to make the group query faster.

ldap.groupSearchFilter

Defines the search filter for groups. In case we need to search the LDAP tree for group membership this needs to be defined. The marker token "{0}" is replaced with the current user’s DN.

Example:

(& (member={0}) (objectclass=group) )

Yes unless groupMembershipAttribute is defined.

ldap.managerDN

If your LDAP server doesn’t support anonymous binding, then we would have to first authenticate itself against the LDAP server.

A DN typically looks like CN=MyUser,CN=Users,DC=mydomain,DC=com although the exact sequence of tokens depends on the LDAP server configuration.

It can be any valid DN as long as LDAP allows this user to query data.

Probably Yes

ldap.managerSecret

The password for the manager DN

Probably Yes

ldap.displayNameLDAPAttribute

The attribute holding the display name. Per default we use the CN of the user entry.

No

ldap.emailAddressLDAPAttribute

The attribute holding the email value.

Per default, we use the field mail.

This field is currently not used so you can leave it blank.

No

ldap.pooled

Whether or not to pool the LDAP connections

No

Example setup below for Active Directory.

ldap.server=ldapserver.yourdomain.com:3268
ldap.rootDN=DC=yourdomain,DC=com
ldap.managerDN=CN=nameofuser,CN=groupforuser,DC=yourdomain,DC=com
ldap.managerSecret=the_very_secret_string
ldap.userSearchBase=
ldap.userSearchFilter=(&(objectClass=person)(|(sAMAccountName={0})(userPrincipalName={0}@*)))
ldap.emailAddressLDAPAttribute=mail
ldap.displayNameLDAPAttribute=displayName
ldap.groupMembershipAttribute=memberOf
#ldap.groupSearchBase=OU=groups
#ldap.groupSearchFilter=(&(member={0})(objectClass=group))

The managerSecret value can either be defined in plain text, or you can encrypt the password from an MQL client using the "mql encrypt" feature.

<MQL> encrypt password the_password_to_be_encrypted;

The encrypted value can be used in the configuration file if you add the prefix enovia:.

If you ran the mql encrypt command in a release between 19x-HF2 and 20x then you must use the prefix enovia-19x. If you ran it in 21x or later, then use enovia-21x as prefix.

Eg.

ldap.managerSecret=enovia:=vc4QGO6tVoYi

1.4.2. ENOVIA/3DExperience Authentication

If the "loginService" is set to "enovia", TIF will authenticate users against the ENOVIA/3DExperience database.

http.webapp.app-id.loginService=enovia
http.webapp.app-id.realm=Webservices

The second value defines the "realm". (See https://www.ietf.org/rfc/rfc2617.txt for more information about realms and basic authentication).

1.4.3. Spnego Authentication

Secondly, an example for spnego:

http.webapp.app-id.loginService=spnego
http.webapp.app-id.spnego.targetName=HTTP/tifserver.exampledomain.com
http.webapp.app-id.realm=Webservices
Instead of specifying the targetName you may instead point out a property file that holds that value under the key targetName. See below:
http.webapp.app-id.loginService=spnego
http.webapp.app-id.spnego.config=${tif.home}/etc/kerberos/spnego.properties
http.webapp.app-id.realm=Webservices

The spnego.properties defines the targetName like this:

${tif.home}/etc/kerberos/spnego.properties
targetName = HTTP/tifserver.exampledomain.com

1.4.4. Application Token Authentication

Application tokens are managed inside TIF and can be used to grant access for remote systems to use webservices hosted in TIF.

The tokens should be sent as Basic authorization header in the request. The actual token value is only revealed once after the Application Token is created, so you need to store that in a secret place.

You need to configure the web-app to use the login service "app-token".

http.webapp.app-id.loginService=app-token
http.webapp.app-id.realm=Webservices

The created application token declares what ENOVIA/3DExperience user to run the action as, and also what roles to assign the security principal with.

If you leave those properties undeclared on the application token, then TIF will fall back to some default values as declared within the module.properties file.

apptoken.default.roles = Employee,Another Role,Third Role
apptoken.default.user = creator

1.5. Configure Security Constraints in WEB.XML

Within the "web.xml" file (webapps/app-id/WEB-INF/web.xml) you need to setup the rules for the application.

If you have not started TIF, you will not find the web.xml file, instead it will be found under webapps/app-id/WEB-INF/web.xml.template. Upon start, TIF will copy over the template file unless the web.xml file is found.

Below is an example when using ENOVIA/Basic authentication and how such might look like.

Note that in this example, each user that is supposed to use the web-services must have the role "WS-Integration-User". Note that depending on login service used (ldap or enovia), the role is either a LDAP role or an ENOVIA/3DExperience role.

<security-constraint>
    <web-resource-collection>
        <web-resource-name>blocked</web-resource-name>
        <url-pattern>/service/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>WS-Integration-User</role-name>
    </auth-constraint>
    <user-data-constraint>
        <transport-guarantee>NONE</transport-guarantee>
    </user-data-constraint>
</security-constraint>
<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Webservices</realm-name>
</login-config>

Below is an example for Spnego:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>blocked</web-resource-name>
        <url-pattern>/service/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>EXAMPLEDOMAIN.COM</role-name>
    </auth-constraint>
</security-constraint>
<login-config>
    <auth-method>SPNEGO</auth-method>
    <realm-name>Webservices</realm-name>
</login-config>