Newer Version Available
AuthProviderPluginClass Class
Namespace
Usage
To create a custom authentication provider for single sign-on, create a class that extends Auth.AuthProviderPluginClass. This class allows you to store the custom configuration for your authentication provider and handle authentication protocols when users log in to Salesforce with their login credentials for an external service provider. In Salesforce, the class that implements this interface appears in the Provider Type drop-down list in Auth. Providers in Setup. Make sure that the user you specify to run the class has “Customize Application” and “Manage Auth. Providers” permissions.
As of API version 39.0, use the abstract class AuthProviderPluginClass to create a custom external authentication provider. This class replaces the AuthProviderPlugin interface. If you’ve already implemented a custom authentication provider plug-in using the interface, it still works. However, use AuthProviderPluginClass to extend your plug-in. If you haven’t created an interface, create a custom authentication provider plug-in by extending this abstract class. For more information, see AuthProviderPluginClass Code Example.
AuthProviderPluginClass Methods
The following are methods for AuthProviderPluginClass.
getCustomMetadataType()
Signature
public String getCustomMetadataType()
Usage
The getCustomMetatadaType() method returns only custom metadata type names. It does not return custom metadata record names. As of API version 39.0, use this method when extending Auth.AuthProviderPluginClass to create a custom external authentication provider.
getUserInfo(authProviderConfiguration, response)
Signature
public Auth.UserData getUserInfo(Map<String,String> authProviderConfiguration, Auth.AuthProviderTokenResponse response)
Parameters
- authProviderConfiguration
- Type: Map<String,String>
- The configuration for the custom authentication provider. When you create a custom metadata type in Salesforce, the configuration populates it with the custom metadata type default values. Or you can set the configuration with values that you enter when you create the custom provider in Auth. Providers in Setup.
- response
- Type: Auth.AuthProviderTokenResponse
-
The OAuth access token, OAuth secret or refresh token, and state provided by the authentication provider to authenticate the current user.
Usage
As of API version 39.0, use this method when extending Auth.AuthProviderPluginClass to create a custom authentication provider.
1HttpRequest req = new HttpRequest();
2String url = 'https://login.salesforce.com/';
3req.setEndpoint(url);
4req.setMethod('GET');
5Http http = new Http();
6HTTPResponse res = http.send(req);handleCallback(authProviderConfiguration, callbackState)
Signature
public Auth.AuthProviderTokenResponse handleCallback(Map<String,String> authProviderConfiguration, Auth.AuthProviderCallbackState callbackState)
Parameters
- authProviderConfiguration
- Type: Map<StringString>
- The configuration for the custom authentication provider. When you create a custom metadata type in Salesforce, the configuration populates with the custom metadata type default values. Or you can set the configuration with values you enter when you create the custom provider in Auth. Providers in Setup.
- callbackState
- Type: Auth.AuthProviderCallbackState
- The class that contains the HTTP headers, body, and queryParams of the authentication request.
Return Value
Type: Auth.AuthProviderTokenResponse
Creates an instance of the AuthProviderTokenResponse class.
Usage
As of API version 39.0, use this method when extending Auth.AuthProviderPluginClass to create a custom authentication provider.
initiate(authProviderConfiguration, stateToPropagate)
Signature
public System.PageReference initiate(Map<String,String> authProviderConfiguration, String stateToPropagate)
Parameters
- authProviderConfiguration
- Type: Map<StringString>
- The configuration for the custom authentication provider. When you create a custom metadata type in Salesforce, the configuration populates with the custom metadata type default values. Or you can set the configuration with values you enter when you create the custom provider in Auth. Providers in Setup.
- stateToPropagate
- Type: String
- The state passed in to initiate the authentication request for the user.
Return Value
Type: System.PageReference
The URL of the page where the user is redirected for authentication.
Usage
As of API version 39.0, use this method when extending Auth.AuthProviderPluginClass to create a custom authentication provider.
refresh(authProviderConfiguration, refreshToken)
Signature
public Auth.OAuthRefreshResult refresh(Map<String,String> authProviderConfiguration, String refreshToken)
Parameters
- authProviderConfiguration
- Type: Map<String,String>
- The configuration for the custom authentication provider. When you create a custom metadata type in Salesforce, the configuration populates with the custom metadata type default values. Or you can set the configuration with values you enter when you create the custom provider in Auth. Providers in Setup.
- refreshToken
- Type: String
- The refresh token for the user who is logged in.
Return Value
Type: Auth.OAuthRefreshResult
Returns the new access token, or an error message if an error occurs.
Usage
A successful request returns a Auth.OAuthRefreshResult with the access token and refresh token in the response. If you receive an error, make sure that you set the error string to the error message. A NULL error string indicates no error.
The refresh method works only with named credentials; it doesn’t respect the standard OAuth refresh flow. The refresh method with named credentials works only if the earlier request returns a 401.
AuthProviderPluginClass Code Example
The following example demonstrates how to implement a custom Auth. provider plug-in using the abstract class, Auth.AuthProviderPluginClass.
1global class Concur extends Auth.AuthProviderPluginClass {
2
3 // Use this URL for the endpoint that the
4 // authentication provider calls back to for configuration.
5 public String redirectUrl;
6 private String key;
7 private String secret;
8
9 // Application redirection to the Concur website for
10 // authentication and authorization.
11 private String authUrl;
12
13 // URI to get the new access token from concur using the GET verb.
14 private String accessTokenUrl;
15
16 // Api name for the custom metadata type created for this auth provider.
17 private String customMetadataTypeApiName;
18
19 // Api URL to access the user in Concur
20 private String userAPIUrl;
21
22 // Version of the user api URL to access data from Concur
23 private String userAPIVersionUrl;
24
25 global String getCustomMetadataType() {
26 return customMetadataTypeApiName;
27 }
28
29 global PageReference initiate(Map<string,string>
30 authProviderConfiguration, String stateToPropagate)
31 {
32 authUrl = authProviderConfiguration.get('Auth_Url__c');
33 key = authProviderConfiguration.get('Key__c');
34
35 // Here the developer can build up a request of some sort.
36 // Ultimately, they return a URL where we will redirect the user.
37 String url = authUrl + '?client_id='+ key +'&scope=USER,EXPRPT,LIST&redirect_uri='+ redirectUrl + '&state=' + stateToPropagate;
38 return new PageReference(url);
39 }
40
41 global Auth.AuthProviderTokenResponse handleCallback(Map<string,string>
42 authProviderConfiguration, Auth.AuthProviderCallbackState state )
43 {
44 // Here, the developer will get the callback with actual protocol.
45 // Their responsibility is to return a new object called
46 // AuthProviderTokenResponse.
47 // This will contain an optional accessToken and refreshToken
48 key = authProviderConfiguration.get('Key__c');
49 secret = authProviderConfiguration.get('Secret__c');
50 accessTokenUrl = authProviderConfiguration.get('Access_Token_Url__c');
51
52 Map<String,String> queryParams = state.queryParameters;
53 String code = queryParams.get('code');
54 String sfdcState = queryParams.get('state');
55
56 HttpRequest req = new HttpRequest();
57 String url = accessTokenUrl+'?code=' + code + '&client_id=' + key +
58 '&client_secret=' + secret;
59 req.setEndpoint(url);
60 req.setHeader('Content-Type','application/xml');
61 req.setMethod('GET');
62
63 Http http = new Http();
64 HTTPResponse res = http.send(req);
65 String responseBody = res.getBody();
66 String token = getTokenValueFromResponse(responseBody, 'Token', null);
67
68 return new Auth.AuthProviderTokenResponse('Concur', token,
69 'refreshToken', sfdcState);
70 }
71
72 global Auth.UserData getUserInfo(Map<string,string>
73 authProviderConfiguration,
74 Auth.AuthProviderTokenResponse response)
75 {
76 //Here the developer is responsible for constructing an
77 //Auth.UserData object
78 String token = response.oauthToken;
79 HttpRequest req = new HttpRequest();
80 userAPIUrl = authProviderConfiguration.get('API_User_Url__c');
81 userAPIVersionUrl = authProviderConfiguration.get
82 ('API_User_Version_Url__c');
83 req.setHeader('Authorization', 'OAuth ' + token);
84 req.setEndpoint(userAPIUrl);
85 req.setHeader('Content-Type','application/xml');
86 req.setMethod('GET');
87
88 Http http = new Http();
89 HTTPResponse res = http.send(req);
90 String responseBody = res.getBody();
91 String id = getTokenValueFromResponse(responseBody,
92 'LoginId',userAPIVersionUrl);
93 String fname = getTokenValueFromResponse(responseBody,
94 'FirstName', userAPIVersionUrl);
95 String lname = getTokenValueFromResponse(responseBody,
96 'LastName', userAPIVersionUrl);
97 String flname = fname + ' ' + lname;
98 String uname = getTokenValueFromResponse(responseBody,
99 'EmailAddress', userAPIVersionUrl);
100 String locale = getTokenValueFromResponse(responseBody,
101 'LocaleName', userAPIVersionUrl);
102 Map<String,String> provMap = new Map<String,String>();
103 provMap.put('what1', 'noidea1');
104 provMap.put('what2', 'noidea2');
105 return new Auth.UserData(id, fname, lname, flname,
106 uname, 'what', locale, null, 'Concur', null, provMap);
107 }
108
109 private String getTokenValueFromResponse(String response,
110 String token, String ns)
111 {
112 Dom.Document docx = new Dom.Document();
113 docx.load(response);
114 String ret = null;
115
116 dom.XmlNode xroot = docx.getrootelement() ;
117 if(xroot != null){ ret = xroot.getChildElement(token, ns).getText();
118 }
119 return ret;
120 }
121
122 }Sample Test Classes
The following example contains test classes for the Concur class.
1@IsTest
2 public class ConcurTestClass {
3
4 private static final String OAUTH_TOKEN = 'testToken';
5 private static final String STATE = 'mocktestState';
6 private static final String REFRESH_TOKEN = 'refreshToken';
7 private static final String LOGIN_ID = 'testLoginId';
8 private static final String USERNAME = 'testUsername';
9 private static final String FIRST_NAME = 'testFirstName';
10 private static final String LAST_NAME = 'testLastName';
11 private static final String EMAIL_ADDRESS = 'testEmailAddress';
12 private static final String LOCALE_NAME = 'testLocalName';
13 private static final String FULL_NAME = FIRST_NAME + ' ' + LAST_NAME;
14 private static final String PROVIDER = 'Concur';
15 private static final String REDIRECT_URL =
16 'http://localhost/services/authcallback/orgId/Concur';
17 private static final String KEY = 'testKey';
18 private static final String SECRET = 'testSecret';
19 private static final String STATE_TO_PROPOGATE = 'testState';
20 private static final String ACCESS_TOKEN_URL =
21 'http://www.dummyhost.com/accessTokenUri';
22 private static final String API_USER_VERSION_URL =
23 'http://www.dummyhost.com/user/20/1';
24 private static final String AUTH_URL =
25 'http://www.dummy.com/authurl';
26 private static final String API_USER_URL =
27 'www.concursolutions.com/user/api';
28
29 // In the real world scenario, the key and value would be read
30 // from the (custom fields in) custom metadata type record.
31 private static Map<String,String> setupAuthProviderConfig ()
32 {
33 Map<String,String> authProviderConfiguration = new Map<String,String>();
34 authProviderConfiguration.put('Key__c', KEY);
35 authProviderConfiguration.put('Auth_Url__c', AUTH_URL);
36 authProviderConfiguration.put('Secret__c', SECRET);
37 authProviderConfiguration.put('Access_Token_Url__c', ACCESS_TOKEN_URL);
38 authProviderConfiguration.put('API_User_Url__c',API_USER_URL);
39 authProviderConfiguration.put('API_User_Version_Url__c',
40 API_USER_VERSION_URL);
41 authProviderConfiguration.put('Redirect_Url__c',REDIRECT_URL);
42 return authProviderConfiguration;
43
44 }
45
46 static testMethod void testInitiateMethod()
47 {
48 String stateToPropogate = 'mocktestState';
49 Map<String,String> authProviderConfiguration = setupAuthProviderConfig();
50 Concur concurCls = new Concur();
51 concurCls.redirectUrl = authProviderConfiguration.get('Redirect_Url__c');
52 PageReference expectedUrl = new PageReference(authProviderConfiguration.get('Auth_Url__c') + '?client_id='+
53 authProviderConfiguration.get('Key__c') +'&scope=USER,EXPRPT,LIST&redirect_uri='+
54 authProviderConfiguration.get('Redirect_Url__c') + '&state=' +
55 STATE_TO_PROPOGATE);
56 PageReference actualUrl = concurCls.initiate(authProviderConfiguration, STATE_TO_PROPOGATE);
57 System.assertEquals(expectedUrl.getUrl(), actualUrl.getUrl());
58 }
59
60 static testMethod void testHandleCallback()
61 {
62 Map<String,String> authProviderConfiguration =
63 setupAuthProviderConfig();
64 Concur concurCls = new Concur();
65 concurCls.redirectUrl = authProviderConfiguration.get
66 ('Redirect_Url_c');
67
68 Test.setMock(HttpCalloutMock.class, new
69 ConcurMockHttpResponseGenerator());
70
71 Map<String,String> queryParams = new Map<String,String>();
72 queryParams.put('code','code');
73 queryParams.put('state',authProviderConfiguration.get('State_c'));
74 Auth.AuthProviderCallbackState cbState =
75 new Auth.AuthProviderCallbackState(null,null,queryParams);
76 Auth.AuthProviderTokenResponse actualAuthProvResponse =
77 concurCls.handleCallback(authProviderConfiguration, cbState);
78 Auth.AuthProviderTokenResponse expectedAuthProvResponse =
79 new Auth.AuthProviderTokenResponse(
80 'Concur', OAUTH_TOKEN, REFRESH_TOKEN, null);
81
82 System.assertEquals(expectedAuthProvResponse.provider,
83 actualAuthProvResponse.provider);
84 System.assertEquals(expectedAuthProvResponse.oauthToken,
85 actualAuthProvResponse.oauthToken);
86 System.assertEquals(expectedAuthProvResponse.oauthSecretOrRefreshToken,
87 actualAuthProvResponse.oauthSecretOrRefreshToken);
88 System.assertEquals(expectedAuthProvResponse.state,
89 actualAuthProvResponse.state);
90
91 }
92
93 static testMethod void testGetUserInfo()
94 {
95 Map<String,String> authProviderConfiguration =
96 setupAuthProviderConfig();
97 Concur concurCls = new Concur();
98
99 Test.setMock(HttpCalloutMock.class, new
100 ConcurMockHttpResponseGenerator());
101
102 Auth.AuthProviderTokenResponse response =
103 new Auth.AuthProviderTokenResponse(
104 PROVIDER, OAUTH_TOKEN ,'sampleOauthSecret', STATE);
105 Auth.UserData actualUserData = concurCls.getUserInfo(
106 authProviderConfiguration, response) ;
107
108 Map<String,String> provMap = new Map<String,String>();
109 provMap.put('key1', 'value1');
110 provMap.put('key2', 'value2');
111
112 Auth.UserData expectedUserData = new Auth.UserData(LOGIN_ID,
113 FIRST_NAME, LAST_NAME, FULL_NAME, EMAIL_ADDRESS,
114 null, LOCALE_NAME, null, PROVIDER, null, provMap);
115
116 System.assertNotEquals(expectedUserData,null);
117 System.assertEquals(expectedUserData.firstName,
118 actualUserData.firstName);
119 System.assertEquals(expectedUserData.lastName,
120 actualUserData.lastName);
121 System.assertEquals(expectedUserData.fullName,
122 actualUserData.fullName);
123 System.assertEquals(expectedUserData.email,
124 actualUserData.email);
125 System.assertEquals(expectedUserData.username,
126 actualUserData.username);
127 System.assertEquals(expectedUserData.locale,
128 actualUserData.locale);
129 System.assertEquals(expectedUserData.provider,
130 actualUserData.provider);
131 System.assertEquals(expectedUserData.siteLoginUrl,
132 actualUserData.siteLoginUrl);
133 }
134
135
136 // Implement a mock http response generator for Concur.
137 public class ConcurMockHttpResponseGenerator implements HttpCalloutMock
138 {
139 public HTTPResponse respond(HTTPRequest req)
140 {
141 String namespace = API_USER_VERSION_URL;
142 String prefix = 'mockPrefix';
143
144 Dom.Document doc = new Dom.Document();
145 Dom.XmlNode xmlNode = doc.createRootElement(
146 'mockRootNodeName', namespace, prefix);
147 xmlNode.addChildElement('LoginId', namespace, prefix)
148 .addTextNode(LOGIN_ID);
149 xmlNode.addChildElement('FirstName', namespace, prefix)
150 .addTextNode(FIRST_NAME);
151 xmlNode.addChildElement('LastName', namespace, prefix)
152 .addTextNode(LAST_NAME);
153 xmlNode.addChildElement('EmailAddress', namespace, prefix)
154 .addTextNode(EMAIL_ADDRESS);
155 xmlNode.addChildElement('LocaleName', namespace, prefix)
156 .addTextNode(LOCALE_NAME);
157 xmlNode.addChildElement('Token', null, null)
158 .addTextNode(OAUTH_TOKEN);
159 System.debug(doc.toXmlString());
160 // Create a fake response
161 HttpResponse res = new HttpResponse();
162 res.setHeader('Content-Type', 'application/xml');
163 res.setBody(doc.toXmlString());
164 res.setStatusCode(200);
165 return res;
166 }
167
168 }
169 }