Mar 31

Print this Post

PeopleSoft and Kerberos integration: Desktop Single Signon Solution

Single Signon refers to the ability of users to navigate freely within a system of multiple applications after only being authenticated once.

It means that user will be asked for his/her login details only once and whenever he/she clicks on a link pointing to other application, then security information is passed from one application to other automatically and there is no additional burden on user to enter login details again. Of course, all these participating application should have Single Signon configured.

With PeopleTools 8.51 onwards, Oracle delivered Kerberos Software Development Kit (SDK) which can be used as Desktop Single Signon Solution. Which means, once the user will get authenticated inside their machine, they need not to give their credentials to get into PeopleSoft application. PeopleSoft authentication will happen on the basis of user’s network login.

The following diagram illustrates the request and response flow between the client, the KerberosSSOFilter, and the portal servlet.

Task details

For PeopleSoft and Kerberos integration, we need to complete below tasks:

• Configure the directory server to act as the Key Distribution Center (KDC).
• Setup Active Directory in PeopleSoft
• Set up Kerberos authentication on the web server.
• Set up Kerberos authentication on the application server.
• Write Signon PeopleCode for Kerberos authentication.
• Configure the PeopleSoft application for Kerberos authentication.
• Modify and Enable Signon PeopleCode to include Kerberos authentication
• Browser Configuration

Configure the Directory Server to Act as the Key Distribution Center (KDC)

To configure your directory server to act as the KDC:

1.    Create an appropriate server user account in the directory.

To add a server user:

a. On a Windows 2003 domain controller, select Start, Control Panels, Administrative Tools, Active Directory Users and Computers.
b. From the menu bar, select Action, New, User.
c. Enter values in the Full name and User logon name fields. You should use your own internal naming conventions. For example, Full name: Kerberos Server, User logon name: krbsrv

Note: The First name, Last name, and Initials fields are not important, but you must specify the Full name and User logon name. Kerberos authentication uses the User logon name only.

d. Click Next.

e. Use this table to set the password and check box values:

User must change password at next logon     Cleared
User cannot change password                      Selected
Password never expires                                Selected
Account is disabled                                      Cleared

f. Click Next and then click Finish.

In my test case, the user name is system123

2. Generate the keytab file. The keytab file stores the name and encrypted password of the server user account.

In my case, keytab file got generated as per below command:

ktpass -princ HTTP/machine.com@AD.ABC -mapuser system123@AD.ABC -crypto RC4-HMAC-NT -ptype KRB5_NT_PRINCIPAL -pass password -out c:krb5.keytab

-princ         Specifies the service principal name in the form user@realm
-mapuser    Maps the name of the Kerberos principal specified by the princ parameter to the specified local user   name
-crypto       Sets the encryption type to use
-ptype        Sets the principal type to Kerberos 5 for Microsoft Windows
-pass         Causes the utility to prompt you for a password
-out           Specifies the name and location of the Kerberos version 5 .keytab file to generate

3. Map the server user credentials to a Service Principal Name (SPN) matching the website that the server hosts (network team).

The SPN can include any possible URL. Valid SPNs for the AD.ABC domain include:

• HTTP/other.domain.net@AD.ABC
• HTTP/localhost@AD.ABC

Set the SPN as per below:

a- Setspn –d HTTP/machine.com ADsystem123
b- Setspn –a HTTP/machine.com ADsystem123


Setup Active Directory in PeopleSoft

Step 1:    Directory Setup

To setup the directory, navigate to the PeopleTools > Security > Directory > Configure Directory page.

Configuring the directory is used for caching the directory schema, which is a required process for LDAP authentication in PeopleTools 8.4.

Although this component has four pages, Directory Setup, Additional DNs, Schema management, and Test Connectivity, to setup LDAP authentication, only the Directory Setup and Test Connectivity pages are important at this point.

All values entered must be correct and not mistyped or signon PeopleCode will not be able to talk to your directory correctly.

Directory ID: Identifies the directory connection that you are creating. The directory ID that you enter can identify a specific LDAP server or a collection of LDAP servers depending on how many servers you add in the Server Name section.

Description: Enter a description of the directory connection.

Directory Product: Select your directory product from the list of options i.e. Microsoft Active Directory, Novell e-Directory, etc. We are using MS Active directory, hence we have selected the same.

Default Connect DN: The Distinguished Name of directory based account with “Browse” rights to ObjectClass=Person entries and “Read” rights to all needed attributes. The DN is the full path to the user, for example cn=administrator,cn=users,dc=peoplesoft,dc=com which means that this user is located in the container called users under the domain called peoplesoft.com. This DN will be chosen by default when creating subsequent maps. The default DN can be overridden on each mapping page by adding addition connect DNs on the following page.

Password: The directory password for User DN. This is important as with no password you are making an anonymous bind to the directory. PeopleSoft suggests not using anonymous to bind to your directory but that is your choice to make. You need a password in order to cache the directory schema, which will be in the next step. The password is stored in encrypted form in the database; not even individuals with administration access to the database can view this password.

Server Name: Add LDAP directory servers to a connection list. You can add multiple servers for failover purposes using the plus button. All servers you add must participate in the same directory service.

LDAP Server: Identify a specific LDAP server. You can use the DNS name or you can use IP address dotted notation. For example, either of the following formats is acceptable: ldap12.yourcompany.com or

Port: Enter the port number on which the LDAP server is configured to receive search requests. The standard LDAP port is 389. If you do not specify the correct port, PeopleSoft Directory Interface can’t exchange data with your LDAP server. In Active Directory you can also choose to use the Global Catalog
port of 3268.

SSL Port: If you are implementing Secure Socket Layer (SSL), enter the SSL port on the LDAP server. The standard SSL port in 636. In Active Directory the Global Catalog port for SSL is 3269.

In our case, the values were as below:

Directory ID:            SYSTEM123
Directory Product:    Microfost Active Directory
Default Connect DN: system123@AD.ABC
LDAP server:           AD.ABC
Port:                       389

Step 2: Test Connectivity

Next we need to verify the settings in Directory Setup page to see if they can pass all the connectivity tests. The page displays the results (SUCCESS or FAIL) of the connectivity test. If connectivity fails, modify the connect information on the Directory Setup and Additional Connect DN’s pages. All tests must return SUCCESS. If they do not then either your configuration settings are not correct or the default connect id used does not have full access to your LDAP Directory. If you have the bind and search of the host returning success, but the search of the schema is failing, then that means you are attempting to bind anonymously, and normally anonymous cannot read the schema. This test verifies that the server and directory are up and running, it makes a bind if you are using a password with the connect DN; otherwise it is making an anonymous bind to the directory. So you may see varied results depending what values you have on your directory setup page.

**Things to check if you get a failure on this page:

i. Test the connect DN without a password, this will do an anonymous bind and should return successfully.
ii. Check the port numbers being used that they are valid.

iii. Check the server name, if you are using DNS names you might try using the IP address instead.
iv. Check to make sure the DN being used is correct.

Step 3: Caching the Directory Schema

You use the Cache Schema page to specify a directory server and invoke an Application Engine program designed to create a cache in the PeopleSoft database of the directory schema. This enables you to select names of Object Classes and Attribute Types when creating security maps. If you have multiple directory configurations you will need to cache the schema for each configuration. The directory authentication and User Profile maps use these attribute values when mapping your directory.

When caching the directory schema you will need to choose the directory and the server. This process should only take a few minutes and it needs to be run for every configuration you create.


Step 4: Setup Authentication Map

This is the information used to bind to the directory and search for the LDAP user that is logging into PeopleSoft.

The first thing is to make sure the map you are using is active.

The Directory ID is the configuration that you previously setup in the configure directory. This must be defined in order to properly fill the Connect DN.

Anonymous Bind and Use Secure Socket Layer are options you can check at this point if you are using that setup. You can only use one option not both or neither and use the default DN.

The Connect DN gets populated automatically when you choose the directory ID from the previous setup. If you wanted to use a different connect DN then you can use the dropdown box which will allow you to choose from the Additional DNs page you may have setup when configuring the directory in step 1. We skipped this page but as mentioned before the Additional DNs page can be used if you want to have other users that can search the directory, that you would want your Authentication map to use instead of the connect DN on the directory setup page The list of servers is brought over from step 1 also. You can choose to add or subtract any servers for this particular map. Be sure to add the appropriate sequence number for the search order of which server will be first searched. The User Search Information is critical. Here is where we have also found a lot of errors made. This is where you will define the Search base, the search scope, and the search attribute used to find the users in the directory.

Search Base: The search base is the container or starting point in the directory that you want to start your search for users. You MUST include the whole DN path for this location.

Scope: The scope of the search, which can be one of these values:

Base retrieves information only at the level of your search base. It will not look deeper in you directory for users.
One retrieves information about entries one level below the base.
Sub retrieves information about entries at all levels below the base. The base entry is included in this scope. If no scope is specified, the server performs a base search.

Search Attribute: The search attribute is the directory attribute of  ObjectClass=Person to which the provided User ID should be matched.


cn=system123,ou=System Accounts,ou=Support,dc=ad,dc=abc

Step 5: Setup User Profile Map

This page is used for mapping you directory users to the PSOPRDEFN table.


Mandatory User Properties page:

Authentication Map: Choose the authentication map, from the dropdown list, that you will be using this profile map with. As stated before you can have multiple authentication maps, therefore you need to have a corresponding profile map with each authentication map. You may ONLY have one User Profile Map per authentication Map.

User ID Attribute: This is the directory attribute containing the value that will be used as the PeopleSoft OPRID on the PSOPRDEFN table. So once the search attribute, on the last page is found, the signon PeopleCode then binds to this directory attribute. This is also the value that will be updated or created in PeopleSoft if you are using the USER_PROFILE component interface. So if your uid or sAMAccountName, in the directory, were jsmith then the OPRID in PeopleSoft would be searching for, or creating would be JSMITH.

Note: Although the directory is case insensitive the delivered peoplecode will ALWAYS force UPPER CASE when returning from the directory and searching the PSOPRDEFN table for this user or when creating the user in the PSOPRDEFN table. So you will notice that your users get created in upper case regardless of their case in the directory. See possible solution in Appendix C to make changes to this delivered functionality.

ID Type: This is the default ID Type for newly created users. Once you have established LDAP authentication and you want to change this to EMP (emplid) you may but bear in mind that when using the value of EMP you must also have the ID Type Attribute value filled with the user’s correct employee number.

ID Type Attribute: The name of the LDAP attribute containing valid data for the given ID Type. If using NON then this filed is grayed out and no value is required. However, if you are using the EMP ID type then the directory attribute named here must contain the same value on the user profile of the directory as the EMPLID value in the PS_PERSONAL_DATA table in PeopleSoft contains for this user, as there is a cross reference to the employee when the user is created. So if you are using EMP as the ID Type and the ID Type Attribute is employeenumber (which would need to be a valid attribute in your directory) then this value on the employeenumber attribute in the directory would have to match the EMPLID for this user on the PS_PERSONAL_DATA table in order to correctly cross reference and update or create the user profile.

Default Role: We have 3 options here.

1) You can choose to assign to your newly created users a default role, that exists in PeopleSoft, that will give only the minimal access you would want EVERY user to have and also allowing the user to logon with only this role.

2) You can choose a directory attribute that will hold the default PeopleSoft role you want to assign to your users, remember with this option you must have an attribute defined in the directory with the PeopleSoft role name value in it for this role to be correctly assigned to the user logging in.

3) You can choose not to assign a default role at all. This is the safest option if you are already dynamically assigning roles to your users, or you are only authenticating users and not creating them through the LDAP_PROFILESYNCH option on the signon peoplecode page.

Note: We cannot use both options 1 & 2 and in using the 3rd option, if you have directory groups named the same as your PeopleSoft roles, then your users will get these roles assigned to them “on the fly” as they logon and their static roles will be deleted.

Additional note: If the user is already created in PeopleSoft, then they will not be assigned the default role when they logon through the LDAP_PROFILESYNCH. This is only for users that have not yet been created on the PSOPRDEFN table.

Default Language Code: This is the same as the default role as you can define to use a default value or a directory attribute. Remember you cannot use both.

Step 6: Setting up Signon PeopleCode

This will be discussed in Kerberos integration as below point:

Modify and Enable Signon PeopleCode to include Kerberos authentication

Set up Kerberos Authentication on the Web Server

To configure the web server JVM for Kerberos authentication:

1. Create a folder specific to kerberos configuration files, such as /usr/krb5 on the server. Place the keytab file in this folder.

2. Create two configuration files:


In my case, the values were below:


default_realm = AD.ABC
ticket_lifetime = 2400
dns_lookup_realm = false
dns_lookup_kdc = true
#default_tkt_enctypes = des-cbc-crc
#default_tgs_enctypes = des-cbc-crc

AD.ABC = {
kdc = AD.ABC
admin_server = AD.ABC
default_domain = AD.ABC



krbServer {
com.sun.security.auth.module.Krb5LoginModule required

3. Configure the web server to use these files for Kerberos authentication, by adding JVM arguments.

a. Edit the setEnv file in the /webserv//bin/ directory.

b. Find the line that begins with SET JAVA_OPTIONS = and append the line with this text:

-Djava.security.auth.login.config=”krb5Login.conf file path with the file name”
-Djava.security.krb5.conf=”krb5.conf file path with the file name”

** In our test case:

JAVA_OPTIONS=”-Xms512m -Xmx512m -XX:MaxPermSize=256m -Dtoplink.xml.platform=oracle.toplink.platform.xml.jaxp.JAXPPlatform -Dcom.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0 -Djava.security.auth.login.config=/UNIX_DIR/krb5Login.conf -Djava.security.krb5.conf=/UNIX_DIR/krb5.conf”

4. Save the file.

Kerberos Java class files should be present in the /webserv/peoplesoft/applications//PORTAL.war/WEB INF/classes/com/peoplesoft/pt/desktopsso/kerberos directory.

• KerberosSSOFilter.class
• KerberosSSOFilter$1.class
• KerberosSSOFilter$KerberosAuthWrapper.class
• KerberosSSOFilter$KerberosHideWrapper.class

Open the web.xml file in the /webserv//applications/peoplesoft/PORTAL.war/WEB INF/ directory

Place below code:



Weblogic console settings:

Configure NegotiateIdentityAsserter from the console. Open the weblogic console by typing the URL:


Home > Summary of Security Realms > myrealm > Providers > Authentication > Create new NegotiateIdentityAsserter

Leave the default Active Types
Under Provider Specific, uncheck Form Based Negotiation Enabled

Activate the changes and restart the server.

Set up Kerberos Authentication on the Application Server

Setting up Kerberos authentication on the application server requires that you configure the application server JVM to validate the Kerberos token:

To configure the application server JVM to validate the Kerberos token:

1. These Java class files should be in the /class/com/peoplesoft/pt/desktopsso/kerberos directory.

• KerberosSSOValidator.class
• KerberosSSOValidator$1.class

Note: In addition to the compiled Java classes, all PeopleSoft applications include the Java source code for the KerberosSSOValidator. You can find the source files in the sdkdesktopssosrccompeoplesoftptdesktopssokerberos directory.

2. Open the application server configuration file: psappsrv.cfg

3. Find the line that begins with JavaVM Options=and append the line with this text:

-Djava.security.auth.login.config=”krb5Login.conf file path with the file name”
-Djava.security.krb5.conf=”krb5.conf file path with the file name”

** In my test case, the values were like below:

JavaVM Options=-Dxdo.ConfigFile=%PS_HOME%/appserv/xdo.cfg -Xms32m -Xmx128m -Djava.security.auth.login.config=/UNIX_DIR/krb5Login.conf -Djava.security.krb5.conf=/UNIX_DIR/krb5.conf

4. Save the file.

Write Signon PeopleCode for Kerberos authentication

1. In PeopleSoft Application Designer, open the FUNCLIB_LDAP record definition. Right-click the LDAPAUTH field and select View PeopleCode.
2. Find the Function getWWWAuthConfig() PeopleCode function.
3. Change the &defaultUserId to “PUBUSER”.
4. In the same field and event, add a KRB_AUTHENTICATION function. We have to add the following function at the end with the below code.

Signon PeopleCode

If %PSAuthResult = True And
&authMethod <> “WWW” And
&authMethod <> “OAMSSO” And
&authMethod <> “OSSO” And
&authMethod <> “SSO” And
&authMethod <> “LDAP” Then
If %SignonUserId =
&defaultUserId Then
Local string &princName =
Local string &krbToken =
Local string &userName =
Local number &foundDelim =
Find(“@”, &userName);
If (&foundDelim > 0) Then
&userName = Substring(
&userName, 1, &foundDelim – 1);
If Len(&userName) > 0 Then
&krbToken = Substring(
&krbToken, 11, Len(&krbToken) + 1);
&validator =
Local string
&validUserName = &validator.validate(
If &validUserName <>
“NULL” And
&princName =
&validUserName Then
SetAuthenticationResult(True, Upper(
&userName), “”, False);
&authMethod = “KRB”;

Configure the PeopleSoft application for Kerberos authentication

To configure the PeopleSoft application to use Kerberos authentication, we need to enable public access.

To enable public access:

1. Select PeopleTools, Web Profile, Web Profile Configuration and open the profile to which you are adding Kerberos authentication.

2. On the Security tab, select the Allow Public Access check box and then enter the user ID and password of the public access PeopleSoft application user. This user should have minimal permissions.

In this example, you see that public access is enabled as the user ID, PUBUSER.


Note: User ID on this page must be the same user ID that you entered in the getWWWAuthConfig() function in the Signon PeopleCode.

3. Save the web profile.

Modify and Enable Signon PeopleCode to include Kerberos authentication

To enable Kerberos authentication Signon PeopleCode:

1. Select PeopleTools, Security, Security Objects, Signon PeopleCode.

2. Insert a new row and enter these values:

Field                    Value or State

Enabled                Selected
Record                 FUNCLIB_LDAP
Field Name           LDAPAUTH
Event Name          FieldDefault
Exec Auth Fail     Selected
Sequence            Enter a value that does not conflict with the flow of other Signon PeopleCode functions.


3. Save the page.

Browser Configuration

Internet Explorer default settings typically work with Kerberos single signon. However, if the browser settings are not the default, you might need to change the browser settings. In addition, Internet Explorer only uses Kerberos authentication for sites in the Local intranet zone. If your PeopleSoft applications are not within this zone, you must add them.

Internet Explorer settings:

1. Open Internet Explorer and select Tools, Internet Options. Then, select the Security tab.
2. In the zones display, select Local intranet and then, click the Sites button.
3. Select the check boxes that apply to the PeopleSoft site.
4. If these settings do not meet your needs, then click the Advanced button and add the site specifically.

After you add the site, click the Close button.

5. On the Local Intranet dialog box, click the OK button.
6. On the Internet Options dialog box, select the Advanced tab. Then, scroll down to the Security settings. Select the Enable Integrated Windows Authentication check box.
7. Click the OK button and then, restart the browser so that the settings take effect.

After completing the configuration, try the URL below to access the PeopleSoft application.


** One should not try the typical PS URL ”http://server:port//signon.html”, as no matter what desktop SSO solution you have implemented, you will land up to the default PeopleSoft login page.

**IMP: If everything regarding the setup is fine, user should get login. However, the testing is not over yet. If the setup is not fine, then also user will get login as there is a public user configured inside the application. User should check their roles and run a CNTL+J test even if their login is fine and check if they are getting their userID only. PeopleSoft application administrator should check the application server and PIA logs for any descripencies or inconsistencies. A Network administrator role is also very important in any troubleshooting.

** First image has been taken from “PeopleSoft Security Administration e-book”


1. PeopleSoft Security Administration
2. Randy’s blog from Remote PeopleSoft admins:


** Special thanks to Randy for his extended support. He helped me out for implementing this solution.

Permanent link to this article: http://alokbhardwaj.com/oracle-peoplesoft/2014/03/31/peoplesoft-and-kerberos-integration-desktop-single-signon-solution/

1 comment

  1. sanatan Gupta

    Hello Alok,

    We are also in process to implement the above desktop SSO in our organization with PeopleSoft Application.
    Our entire architecture of PS is based on AIX 6.1 Application version is 9.1 and Tool version is 8.52.11

    I have done all the configuration as per the above steps but unable to get it done.

    Through the login url ,we are getting logged in with the public user that we mentioned in web profile page.
    Alo in the weblogic log we are getting following error –

    <Could not load user defined filter in web.xml: com.peoplesoft.pt.desktopsso.kerberos.KerberosSSOFilter.
    java.lang.IllegalArgumentException: No Configuration was registered that can handle the configuration named krbServer
    at com.bea.common.security.jdkutils.JAASConfiguration.getAppConfigurationEntry(JAASConfiguration.java:130)
    at javax.security.auth.login.LoginContext.init(LoginContext.java:267)
    at javax.security.auth.login.LoginContext.(LoginContext.java:366)
    at com.peoplesoft.pt.desktopsso.kerberos.KerberosSSOFilter.init(KerberosSSOFilter.java:142)
    at weblogic.servlet.internal.FilterManager$FilterInitAction.run(FilterManager.java:332)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
    at weblogic.servlet.internal.FilterManager.loadFilter(FilterManager.java:98)
    at weblogic.servlet.internal.FilterManager.preloadFilters(FilterManager.java:59)
    at weblogic.servlet.internal.WebAppServletContext.preloadResources(WebAppServletContext.java:1876)
    at weblogic.servlet.internal.WebAppServletContext.start(WebAppServletContext.java:3153)
    at weblogic.servlet.internal.WebAppModule.startContexts(WebAppModule.java:1508)
    at weblogic.servlet.internal.WebAppModule.start(WebAppModule.java:482)
    at weblogic.application.internal.flow.ModuleStateDriver$3.next(ModuleStateDriver.java:425)
    at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:52)
    at weblogic.application.internal.flow.ModuleStateDriver.start(ModuleStateDriver.java:119)
    at weblogic.application.internal.flow.ScopedModuleDriver.start(ScopedModuleDriver.java:200)
    at weblogic.application.internal.flow.ModuleListenerInvoker.start(ModuleListenerInvoker.java:247)
    at weblogic.application.internal.flow.ModuleStateDriver$3.next(ModuleStateDriver.java:425)
    at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:52)
    at weblogic.application.internal.flow.ModuleStateDriver.start(ModuleStateDriver.java:119)
    at weblogic.application.internal.flow.StartModulesFlow.activate(StartModulesFlow.java:27)
    at weblogic.application.internal.BaseDeployment$2.next(BaseDeployment.java:636)
    at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:52)
    at weblogic.application.internal.BaseDeployment.activate(BaseDeployment.java:205)
    at weblogic.application.internal.EarDeployment.activate(EarDeployment.java:58)
    at weblogic.application.internal.DeploymentStateChecker.activate(DeploymentStateChecker.java:161)
    at weblogic.deploy.internal.targetserver.AppContainerInvoker.activate(AppContainerInvoker.java:79)
    at weblogic.deploy.internal.targetserver.BasicDeployment.activate(BasicDeployment.java:184)
    at weblogic.deploy.internal.targetserver.BasicDeployment.activateFromServerLifecycle(BasicDeployment.java:361)
    at weblogic.management.deploy.internal.DeploymentAdapter$1.doActivate(DeploymentAdapter.java:51)
    at weblogic.management.deploy.internal.DeploymentAdapter.activate(DeploymentAdapter.java:200)
    at weblogic.management.deploy.internal.AppTransition$2.transitionApp(AppTransition.java:30)
    at weblogic.management.deploy.internal.ConfiguredDeployments.transitionApps(ConfiguredDeployments.java:240)
    at weblogic.management.deploy.internal.ConfiguredDeployments.activate(ConfiguredDeployments.java:169)
    at weblogic.management.deploy.internal.ConfiguredDeployments.deploy(ConfiguredDeployments.java:123)
    at weblogic.management.deploy.internal.DeploymentServerService.resume(DeploymentServerService.java:180)
    at weblogic.management.deploy.internal.DeploymentServerService.start(DeploymentServerService.java:96)
    at weblogic.t3.srvr.SubsystemRequest.run(SubsystemRequest.java:64)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:207)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:176)

    Please help on this. Thanks in advance.


Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>