Skip to content

Commit

Permalink
Merge pull request #2783 from atmire/w2p-71342_Authorization-for-Down…
Browse files Browse the repository at this point in the history
…loads-of-restricted-Bitstreams-1

Authorization for Downloads of restricted Bitstreams: Short lived token endpoint
  • Loading branch information
tdonohue committed Jul 1, 2020
2 parents cc362d8 + 9044daf commit 338bb22
Show file tree
Hide file tree
Showing 19 changed files with 859 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
import org.dspace.app.rest.converter.EPersonConverter;
import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.AuthenticationStatusRest;
import org.dspace.app.rest.model.AuthenticationTokenRest;
import org.dspace.app.rest.model.AuthnRest;
import org.dspace.app.rest.model.EPersonRest;
import org.dspace.app.rest.model.hateoas.AuthenticationStatusResource;
import org.dspace.app.rest.model.hateoas.AuthenticationTokenResource;
import org.dspace.app.rest.model.hateoas.AuthnResource;
import org.dspace.app.rest.model.wrapper.AuthenticationToken;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.security.RestAuthenticationService;
import org.dspace.app.rest.utils.ContextUtil;
Expand All @@ -32,6 +35,7 @@
import org.springframework.hateoas.Link;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
Expand Down Expand Up @@ -118,6 +122,30 @@ public ResponseEntity login(HttpServletRequest request, @RequestParam(name = "us
"valid.");
}

/**
* This method will generate a short lived token to be used for bitstream downloads among other things.
*
* curl -v -X POST https://{dspace-server.url}/api/authn/shortlivedtokens -H "Authorization: Bearer eyJhbG...COdbo"
*
* Example:
* <pre>
* {@code
* curl -v -X POST https://{dspace-server.url}/api/authn/shortlivedtokens -H "Authorization: Bearer eyJhbG...COdbo"
* }
* </pre>
* @param request The StandardMultipartHttpServletRequest
* @return The created short lived token
*/
@PreAuthorize("hasAuthority('AUTHENTICATED')")
@RequestMapping(value = "/shortlivedtokens", method = RequestMethod.POST)
public AuthenticationTokenResource shortLivedToken(HttpServletRequest request) {
Projection projection = utils.obtainProjection();
AuthenticationToken shortLivedToken =
restAuthenticationService.getShortLivedAuthenticationToken(ContextUtil.obtainContext(request), request);
AuthenticationTokenRest authenticationTokenRest = converter.toRest(shortLivedToken, projection);
return converter.toResource(authenticationTokenRest);
}

@RequestMapping(value = "/login", method = { RequestMethod.GET, RequestMethod.PUT, RequestMethod.PATCH,
RequestMethod.DELETE })
public ResponseEntity login() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.converter;

import org.dspace.app.rest.model.AuthenticationTokenRest;
import org.dspace.app.rest.model.wrapper.AuthenticationToken;
import org.dspace.app.rest.projection.Projection;
import org.springframework.stereotype.Component;

/**
* This is the converter from the AuthenticationToken to the REST data model
*/
@Component
public class AuthenticationTokenConverter implements DSpaceConverter<AuthenticationToken, AuthenticationTokenRest> {
@Override
public AuthenticationTokenRest convert(AuthenticationToken modelObject, Projection projection) {
AuthenticationTokenRest token = new AuthenticationTokenRest();
token.setToken(modelObject.getToken());
return token;
}

@Override
public Class<AuthenticationToken> getModelClass() {
return AuthenticationToken.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.link;

import java.util.LinkedList;

import org.dspace.app.rest.AuthenticationRestController;
import org.dspace.app.rest.model.hateoas.AuthenticationTokenResource;
import org.springframework.data.domain.Pageable;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.stereotype.Component;

/**
* This class adds the self link to the AuthenticationTokenResource.
*/
@Component
public class AuthenticationTokenHalLinkFactory
extends HalLinkFactory<AuthenticationTokenResource, AuthenticationRestController> {

@Override
protected void addLinks(AuthenticationTokenResource halResource, Pageable pageable, LinkedList<Link> list)
throws Exception {

list.add(buildLink(IanaLinkRelations.SELF.value(), getMethodOn().shortLivedToken(null)));
}

@Override
protected Class<AuthenticationRestController> getControllerClass() {
return AuthenticationRestController.class;
}

@Override
protected Class<AuthenticationTokenResource> getResourceClass() {
return AuthenticationTokenResource.class;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class AuthenticationStatusRest extends BaseObjectRest<Integer> {
private boolean authenticated;

public static final String NAME = "status";
public static final String CATEGORY = "authn";
public static final String CATEGORY = RestAddressableModel.AUTHENTICATION;

@Override
public String getCategory() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.model;

import org.dspace.app.rest.RestResourceController;

/**
* The authentication token REST HAL Resource. The HAL Resource wraps the REST Resource
* adding support for the links and embedded resources
*/
public class AuthenticationTokenRest extends RestAddressableModel {
public static final String NAME = "shortlivedtoken";
public static final String CATEGORY = RestAddressableModel.AUTHENTICATION;

private String token;

@Override
public String getCategory() {
return CATEGORY;
}

@Override
public Class getController() {
return RestResourceController.class;
}

@Override
public String getType() {
return NAME;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
public class AuthnRest extends BaseObjectRest<Integer> {

public static final String NAME = "authn";
public static final String CATEGORY = "authn";
public static final String CATEGORY = RestAddressableModel.AUTHENTICATION;

public String getCategory() {
return CATEGORY;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public interface RestModel extends Serializable {
public static final String WORKFLOW = "workflow";
public static final String AUTHORIZATION = "authz";
public static final String VERSIONING = "versioning";
public static final String AUTHENTICATION = "authn";

public String getType();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.model.hateoas;

import org.dspace.app.rest.model.AuthenticationTokenRest;

/**
* Token resource, wraps the AuthenticationToken object
*/
public class AuthenticationTokenResource extends HALResource<AuthenticationTokenRest> {

public AuthenticationTokenResource(AuthenticationTokenRest content) {
super(content);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.model.wrapper;

/**
* This class represents an authentication token. It acts as a wrapper for a String object to differentiate between
* actual Strings and AuthenticationToken
*/
public class AuthenticationToken {
private String token;

public AuthenticationToken(String token) {
this.token = token;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dspace.app.rest.security.jwt.JWTTokenHandler;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.core.Context;
import org.slf4j.Logger;
Expand All @@ -29,7 +28,7 @@
@Component
public class CustomLogoutHandler implements LogoutHandler {

private static final Logger log = LoggerFactory.getLogger(JWTTokenHandler.class);
private static final Logger log = LoggerFactory.getLogger(CustomLogoutHandler.class);

@Autowired
private RestAuthenticationService restAuthenticationService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dspace.app.rest.model.wrapper.AuthenticationToken;
import org.dspace.authenticate.service.AuthenticationService;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
Expand All @@ -28,6 +29,14 @@ public interface RestAuthenticationService {
void addAuthenticationDataForUser(HttpServletRequest request, HttpServletResponse response,
DSpaceAuthentication authentication, boolean addCookie) throws IOException;

/**
* Retrieve a short lived authentication token, this can be used (among other things) for file downloads
* @param context the DSpace context
* @param request The current client request
* @return An AuthenticationToken that contains a string with the token
*/
AuthenticationToken getShortLivedAuthenticationToken(Context context, HttpServletRequest request);

EPerson getAuthenticatedEPerson(HttpServletRequest request, Context context);

boolean hasAuthenticationData(HttpServletRequest request);
Expand Down
Loading

0 comments on commit 338bb22

Please sign in to comment.