๐Ÿ‡จ๐Ÿ‡ณ ืกื ื›ืจื•ืŸ ื ืชื•ื ื™ ืžืฉืชืžืฉ ื‘ืชื•ืš DiscourseConnect ื‘ืืžืฆืขื•ืช sync_sso [Java] | ืฉื™ืžื•ืฉ ื‘- sync_sso ืœืกื ื›ืจื•ืŸ ื ืชื•ื ื™ ืžืฉืชืžืฉ ืฉืœ DiscourseConnect [Java]

ืกื™ื›ื•ื ืžื‘ื•ืกืก ื‘ื™ื ื” ืžืœืื›ื•ืชื™ืช

honeymoose ๅˆ†ไบซไบ†ไธ€ไธชไฝฟ็”จ Java ๅฎž็Žฐ DiscourseConnect ็”จๆˆทๆ•ฐๆฎๅŒๆญฅ็š„ๆ–นๆกˆ๏ผŒๅŸบไบŽๅฎ˜ๆ–น PHP ็คบไพ‹ใ€‚ๅฎž็Žฐไพ่ต– Apache Commons Codec๏ผˆ็”จไบŽ HMAC_SHA_256 ๆ•ฐๅญ—็ญพๅ๏ผ‰ๅ’Œ OkHttp๏ผˆ็”จไบŽๅ‘้€ HTTP POST ่ฏทๆฑ‚๏ผ‰ใ€‚้œ€้ข„ๅ…ˆ้…็ฝฎๅ››ไธชๅ‚ๆ•ฐ๏ผšapiKeyใ€apiUserใ€connectSecret ๅŠ SSO ๅ‚ๆ•ฐ๏ผˆๅฆ‚ external_id, email, username ็ญ‰๏ผ‰๏ผŒ้€š่ฟ‡ URIBuilder ๆž„ๅปบๆŸฅ่ฏขๅญ—็ฌฆไธฒใ€‚ๆŽฅ็€ๅฏนๅญ—็ฌฆไธฒ่ฟ›่กŒ Base64 ็ผ–็ ๏ผŒๅ†็”จๅฏ†้’ฅ็”Ÿๆˆ็ญพๅ๏ผŒๆœ€็ปˆๅฐ่ฃ…ไธบ JSON ๆ ผๅผ๏ผˆๅซ sso ๅ’Œ sig ๅญ—ๆฎต๏ผ‰ๅ‘้€่‡ณ /admin/users/sync_sso ๆŽฅๅฃใ€‚่ฏทๆฑ‚ๅคด้œ€ๅŒ…ๅซ api-username ๅ’Œ api-key๏ผŒไฝฟ็”จ OkHttp ๆ‰ง่กŒ POST ่ฐƒ็”จๅณๅฏๅฎŒๆˆๅŒๆญฅใ€‚ๅฎŒๆ•ดๅฎž็Žฐๅฏๅ‚่€ƒ Discourse ไฝฟ็”จ DiscourseConnect ๆฅ่ฟ›่กŒ็”จๆˆทๆ•ฐๆฎๅŒๆญฅใ€‚

Recently, there was a need to synchronize existing users to Discourse using SSO.

Therefore, based on the official PHP implementation (Sync DiscourseConnect user data with the sync_sso route - developers - Discourse Meta), I wrote a Java implementation.

The implementation method is very simple, but it requires some additional packages, most importantly Apache Commons Codec and Okhttp.

Apache Commons Codec is used to generate digital signatures, and Okhttp is used to send Http Post requests.

Setting Related Parameters

There are 4 parameters that need to be obtained in advance.

For how to obtain the following 4 parameters, please refer to the article: Discourse User Data Synchronization Using DiscourseConnect

const apiKey = '4fe83002bb5fba8c9a61a65e5b4b0a3cf8233b0e4ccafc85ebd6607abab4651a';
const apiUser = 'system';
const connectSecret = 'jdhb19*Xh3!nu(#k';

Setting SSO Parameters

The parameter settings refer to the parameter settings of the URL Get method.

Our Java code is:

            URIBuilder builder = new URIBuilder();
            builder.addParameter("external_id", "1");
            builder.addParameter("email", "info@isharkfly.com");
            builder.addParameter("username", "info.visafn.sso");
            builder.addParameter("add_groups", "bar");
            builder.addParameter("require_activation", "false");
             url = StringUtils.removeStart(builder.build().toString(),"?");
            System.out.println(StringUtils.removeStart(url, "?"));

Base64 and Digital Signature

After obtaining the URL string above, we have 2 more steps to do.

The first step is to Base64 encode the obtained URL.

The second step is to digitally sign the obtained Base64 string. The HMAC_SHA_256 algorithm is used for signing.

At the same time, the key obtained in the first step needs to be used as a parameter to participate in the calculation along with the algorithm.

        String sso= "admin/users/sync_sso";
        String sig= new HmacUtils(HmacAlgorithms.HMAC_SHA_256, "55619458534897").hmacHex(ssoPayload);

After obtaining the above 2 values, reconstruct a Json data structure.

Similar to the data structure below, and then use it as Post parameter data:

{
    "sso": "P2V4dGVybmFsX2lkPTEmZW1haWw9aW5mbyU0MHZpc2Fmbi5jb20mdXNlcm5hbWU9aW5mby52aXNhZm4mcmVxdWlyZV9hY3RpdmF0aW9uPXRydWU=",
    "sig": "403a205a004e37ffab2bf77cc12b2eac352d71820983706d86984eec9821a0c4"
}

Sending POST Request

Any tool that supports HTTP can be used.

OkHttp is commonly used in Java now, so we will use OkHttp to send the request.

private OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(
                    MediaType.parse("application/json"), objectMapper.writeValueAsString(syncSSO));
            Response response = client.newCall(postRequest(path, body)).execute();

The postRequest above is a method where we construct the request using the existing parameters.

The method is written as follows:

    public Request postRequest(String path, RequestBody body) {
        HttpUrl.Builder urlBuilder = HttpUrl.parse(site_url + path).newBuilder();
        Request request = new Request.Builder().url(urlBuilder.build().toString())
                .addHeader("api-username", api_username)
                .addHeader("api-key", api_key)
                .post(body)
                .build();
        return request;
    }

If there are no problems, the code above can complete the SSO data synchronization call.