Skip to content

Commit

Permalink
Feature/821 bb rest 3lo try2 (#1781)
Browse files Browse the repository at this point in the history
* #821 MVP code for 3LO auth

* Three legged authentication for Blackboard. (Incomplete)

* #819 - Courses now cache

Co-authored-by: Diego del Blanco <ddelblanco@unicon.net>
  • Loading branch information
cbeach47 and ddelblanco committed Jun 25, 2020
1 parent 4f76863 commit a04be04
Show file tree
Hide file tree
Showing 20 changed files with 896 additions and 264 deletions.
4 changes: 4 additions & 0 deletions Source/Plugins/Core/com.equella.core/plugin-jpf.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4271,6 +4271,10 @@
<parameter id="type" value="blackboardrest" />
<parameter id="class" value="bean:com.tle.core.connectors.blackboard.service.BlackboardRESTConnectorService" />
</extension>
<extension plugin-id="com.tle.web.core" point-id="webServlet" id="blackboardRestOAuthServlet">
<parameter id="bean" value="bean:com.tle.web.connectors.blackboard.servlet.BlackboardRestOauthSignonServlet" />
<parameter id="url-pattern" value="/blackboardrestauth" />
</extension>
<extension plugin-id="com.tle.core.connectors" point-id="connectorType" id="blackboardConnector">
<parameter id="id" value="blackboard" />
<parameter id="nameKey" value="com.equella.core.connector.name" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1717,8 +1717,12 @@ export.added.summary.singleresource.contentpackage=This content package
export.added.summary.singleresource.resourcesummary=This summary page
export.added.summary.singleresourcemultilocations={0} was published to {1} locations
export.attachments=Include files
export.authorization.newtab.description=This external connector needs to be launched in a new tab. Once the authorization flow is complete, close the new tab, and click OK in this dialog.
export.authorization.newtab.launch=Launch Authorization in New Tab
export.authorization.newtab.receipt=Authorization is complete. Please close this tab and click OK in the dialog in the original tab.
export.button.auth=Authorise external system
export.button.export=Add selected resources
export.button.refreshcache=Refresh Course Cache
export.error.accessdenied=Access denied
export.error.nolocationsselected=No locations are selected to add resources to
export.error.noresourcesselected=No resources are selected to add
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,12 @@

<@css "blackboardconnector.css" />

<@setting label='' help=b.key('bb.editor.help.installmodule')>
<hr>
</@setting>

<@ajax.div id="blackboardsetup">
<@ajax.div id="blackboardrestsetup">

<#include "/com.tle.web.connectors@/field/serverurl.ftl" />

<#if m.testedUrl??>

<@ajax.div id="testdiv">

<@setting
label=''
error=m.errors["blackboardwebservice"]
help=b.key('editor.help.testwebservice')
rowStyle="testBlackboardRow">

<@button section=s.testWebServiceButton showAs="verify" />
<#if m.testWebServiceStatus??>
<span class="status ${m.testWebServiceStatus}">${b.key('bb.editor.label.testwebservice.' + m.testWebServiceStatus)}</span>
</#if>
</@setting>
</@ajax.div>

<@setting label=b.key('blackboardrest.editor.label.apikey')
error=m.errors["apikey"]
help=b.key('blackboardrest.editor.help.apikey')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,24 @@
<@css "auth.css" />

<div id="auth_container">
<iframe frameBorder="0" src="${m.authUrl?html}"></iframe>
</div>
<#if m.showReceipt >
<p>${b.key('export.authorization.newtab.receipt')}</p>
<#else>
<#if m.showNewTabLauncher >
<p>${b.key('export.authorization.newtab.description')}</p>

<button onclick="newTabAuth()" class="btn btn-equella">
${b.key('export.authorization.newtab.launch')}
</button>

<script>
function newTabAuth() {
window.open(
"${m.authUrl}", "_blank", "noopener,noreferrer");
}
</script>
<#else>
<iframe frameBorder="0" src="${m.authUrl?html}"></iframe>
</#if>
</#if>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,18 @@
</div>
</div>
</div>



<#if m.courseCaching>
<div class="button-strip">
<@render s.refreshCourseCacheButton />
</div>
</#if>

<div class="button-strip">
<@render s.publishButton />
</div>

</#if>

</@div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ void logItemContentViewed(

void logItemPurged(Item item);

// Note: This is specific to the Blackboard REST connector,
// however, no other connector uses the audit log yet. Maybe need to refactor in the future
void logExternalConnectorUsed(
String externalConnectorUrl,
String requestLimit,
String requestRemaining,
String timeToReset);

void logGeneric(
String category, String type, String data1, String data2, String data3, String data4);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class AuditLogServiceImpl implements AuditLogService {
private static final String ENTITY_CATEGORY = "ENTITY";
private static final String SEARCH_CATEGORY = "SEARCH";
private static final String ITEM_CATEGORY = "ITEM";
private static final String EXTERNAL_CONN_CATEGORY = "EXTERNAL_CONNECTOR";

private static final String CREATED_TYPE = "CREATED";
private static final String MODIFIED_TYPE = "MODIFIED";
Expand All @@ -60,6 +61,8 @@ public class AuditLogServiceImpl implements AuditLogService {

private static final String SEARCH_FEDERATED_TYPE = "FEDERATED";

private static final String USED_TYPE = "USED";

private static final String TRUNCED = "...";

private PluginTracker<AuditLogExtension> extensionTracker;
Expand Down Expand Up @@ -197,6 +200,21 @@ public void logItemPurged(Item item) {
null);
}

@Override
public void logExternalConnectorUsed(
String externalConnectorUrl,
String requestLimit,
String requestRemaining,
String timeToReset) {
logGeneric(
EXTERNAL_CONN_CATEGORY,
USED_TYPE,
externalConnectorUrl,
requestLimit,
requestRemaining,
timeToReset);
}

private void logEntityGeneric(String type, long entityId) {
logGeneric(ENTITY_CATEGORY, type, CurrentUser.getUserID(), Long.toString(entityId), null, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,28 @@

package com.tle.core.connectors.blackboard;

/** @author Aaron */
@SuppressWarnings("nls")
public final class BlackboardRESTConnectorConstants {
private BlackboardRESTConnectorConstants() {
throw new Error();
}

public static final String AUTHENTICATIONCODE_SERVICE_URI_PATH =
"/learn/api/public/v1/oauth2/authorizationcode";

public static final String SESSION_KEY_USER_ID = "BbRest.UserId";
public static final String SESSION_COURSES = "BbRest.UserCourses";
public static final String SESSION_CODE = "BbRest.Code";
public static final String SESSION_TOKEN = "BbRest.Token";

public static final String CONNECTOR_TYPE = "blackboardrest";

public static final String FIELD_TESTED_WEBSERVICE = "testedWebservice";
public static final String FIELD_API_KEY = "apiKey";
public static final String FIELD_API_SECRET = "apiSecret";

public static final String STATE_KEY_FORWARD_URL = "forwardUrl";
public static final String STATE_KEY_POSTFIX_KEY = "postfixKey";

public static final String AUTH_URL = "blackboardrestauth";

private BlackboardRESTConnectorConstants() {
throw new Error();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* The Apereo Foundation licenses this file to you under the Apache License,
* Version 2.0, (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.tle.core.connectors.blackboard;

import com.tle.annotation.Nullable;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;

public class BlackboardRestAppContext {
private static final String STATE_PARAMETER = "state";
private static final String FIELD_REDIRECT_URI = "redirect_uri";
private static final String KEY_VALUE_RESPONSE_TYPE_CODE = "response_type=code";
private static final String FIELD_CLIENT_ID = "client_id";
private static final String FIELD_SCOPE = "scope";
private static final String VALUE_READ_WRITE_DELETE = "read write delete";

private final String _appId;
private final String _appKey;
private String _url;

/**
* Constructs a BlackboardRestAppContext with the provided application values
*
* @param appId The application ID provided by the key tool
* @param appKey The application key provided by the key tool
* @param url The url of the Bb instance
*/
public BlackboardRestAppContext(String appId, String appKey, String url) {
_appId = appId;
_appKey = appKey;
if (url != null && url.endsWith("/")) {
_url = url.substring(0, url.lastIndexOf("/"));
} else {
_url = url;
}
}

public URI createWebUrlForAuthentication(URI redirectUrl, @Nullable String state) {
try {
URI uri =
new URI(
_url
+ BlackboardRESTConnectorConstants.AUTHENTICATIONCODE_SERVICE_URI_PATH
+ "?"
+ buildAuthenticationCodeUriQueryString(redirectUrl, state));
return uri;
} catch (URISyntaxException e) {
return null;
}
}

private String buildAuthenticationCodeUriQueryString(URI callbackUri, @Nullable String state) {
String callbackUriString = callbackUri.toString();
String result = KEY_VALUE_RESPONSE_TYPE_CODE;
result += "&" + FIELD_REDIRECT_URI + "=" + callbackUriString;
result += "&" + FIELD_CLIENT_ID + "=" + _appId;
result += "&" + FIELD_SCOPE + "=" + URLEncoder.encode(VALUE_READ_WRITE_DELETE);
if (state != null) {
result += "&" + STATE_PARAMETER + "=" + URLEncoder.encode(state);
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@

package com.tle.core.connectors.blackboard.beans;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Availability {
public class Availability implements Serializable {
public static final String YES = "Yes";
public static final String NO = "No";
private String available; // Yes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@

package com.tle.core.connectors.blackboard.beans;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Course {
public class Course implements Serializable {
private String id;
private String uuid;
private String externalId;
Expand Down Expand Up @@ -168,7 +169,7 @@ public void setGuestAccessUrl(String guestAccessUrl) {
}

@XmlRootElement
public static class Enrollment {
public static class Enrollment implements Serializable {
private String type; // InstructorLed

public String getType() {
Expand All @@ -181,7 +182,7 @@ public void setType(String type) {
}

@XmlRootElement
public static class Locale {
public static class Locale implements Serializable {
private Boolean force;

public Boolean getForce() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* The Apereo Foundation licenses this file to you under the Apache License,
* Version 2.0, (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.tle.core.connectors.blackboard.beans;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class CourseByUser {
private Course course;

public Course getCourse() {
return course;
}

public void setCourse(Course course) {
this.course = course;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* The Apereo Foundation licenses this file to you under the Apache License,
* Version 2.0, (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.tle.core.connectors.blackboard.beans;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class CoursesByUser extends PagedResults<CourseByUser> {}
Loading

0 comments on commit a04be04

Please sign in to comment.