Nothing
#
# This work was created by participants in the DataONE project, and is
# jointly copyrighted by participating institutions in DataONE. For
# more information on DataONE, see our web site at http://dataone.org.
#
# Copyright 2012-2014
#
# Licensed 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.
#
#' CertficateManager provides mechanisms to obtain, load, verify, and display X509 certificates.
#' @description CertficateManager provides management functions for X.509 certificates that are
#' used to authenticate connections to DataONE nodes over SSL. The X.509 certificates are issued
#' by a recognized Certificate Authority, typically CILogon, and include fields that provide
#' information about the authenticated party, including the distinguished name of the subject, the
#' dates of validity of the certificate, and other information needed for authorization decisions.
#' Certificate validity is determined by examining the validity of the certificate signatures for
#' each certificate in a chain leading to a trusted root certificate. Within DataONE, the current
#' trusted root certificate authorities are CILogon and DataONE itself.
#'
#' @details
#' Understanding how your identity is managed is important for working with DataONE, especially to
#' avoid unexpected results. For example, depending your authorization status, searches may or may
#' return only public records, or the full set of public and private records. Object and package
#' retrievals might fail if some or all of the objects being retrieved are private. Creating or
#' updating objects on DataONE nodes and reserving identifiers reservations might fail if your
#' authorization certificate is missing or expired.
#'
#' DataONE identifies you using CILogon-provided x509 certificates. DataONE has
#' partnered with CILogon to provide a widely-accessible certificate issuing mechanism
#' that allows DataONE users to use existing trusted institutional and public accounts.
#'
#' CILogon recognizes many identity providers, including many universities as well as
#' Google, so most times users new to DataONE can get certificates using one
#' of their existing accounts. For more information about the CILogon service, see
#' "https://cilogon.org/?skin=DataONE" .
#'
#' X509 Certificates differ from typical username-password login schemes in that
#' certificates can be used by more than one application, which is very useful when
#' using more than one DataONE-enabled application. The certificates CILogon issues
#' for DataONE are so-called "short-lived" certificates that currently expire 18 hours
#' from the time of issuing. Typically you will want to download a fresh certificate
#' the first time you interact with DataONE each day.
#'
#' @slot location value of type \code{"character"}, containing a path to a custom certificate location
#' @slot obscuredpath value of type \code{"character"}, containing the path used to temporarily obscure a certificate
#' @author Matthew Jones, Rob Nahf
#' @rdname CertificateManager-class
#' @keywords classes
#' @section Methods:
#' \itemize{
#' \item{\code{\link{CertificateManager}}}{: Create a CertificateManager object.}
#' \item{\code{\link{getCertLocation}}}{: Get the file path on disk of the client certificate file.}
#' \item{\code{\link{showClientSubject}}}{: Get DataONE Identity as Stored in the CILogon Certificate.}
#' \item{\code{\link{isCertExpired}}}{: Determine if an X.509 certificate has expired.}
#' \item{\code{\link{getCertExpires}}}{: Show the date and time when an X.509 certificate expires.}
#' \item{\code{\link{downloadCert}}}{: Open the CILogon Certificate download page in the default browser.}
#' \item{\code{\link{obscureCert}}}{: Obscure the CILogon Client Certificate.}
#' \item{\code{\link{restoreCert}}}{: Restore the CILogon client certificate by renaming it to its original location}
#' }
#' @seealso \code{\link{dataone}}{ package description.}
#' @examples
#' \dontrun{
#' cm <- suppressWarnings(CertificateManager())
#' cert <- getCertLocation(cm)
#' subject <- showClientSubject(cm)
#' expires <- getCertExpires(cm)
#' isExpired <- isCertExpired(cm)
#' cm <- obscureCert(cm)
#' cm <- restoreCert(cm)
#' }
setClass("CertificateManager", slots = c(
location="character",
obscuredpath="character"
)
)
#' Create a CertificateManager object
#' @description Construct an instance of CertficateManager to provide mechanisms to obtain, load, verify, and
#' display X509 certificates. If the \code{'location'} field is provided, then that location is interpreted
#' as the fully qualified path to a certificate on the local filesystem, and the default locations will not be
#' searched. If \code{'location'} is missing, then the default Globus Grid Security Infrastructure (GSI)
#' location is searched, which is \code{'/tmp/x509up_u${UID}'} on Unix
#' or \code{'${tmpdir}/x509up_u${UID}'} on Windows or \code{'${tmpdir}/x509up_u${user.name}'} if \code{'${UID}'}
#' is not defined.
#' @param ... (Not yet used)
#' @return the CertificateManager object
#' @export
setGeneric("CertificateManager", function(...) {
.Deprecated("AuthenticationManager", "dataone")
standardGeneric("CertificateManager")
})
#' @rdname CertificateManager
setMethod("CertificateManager", signature=character(), function() {
if (!requireNamespace("openssl", quietly = TRUE)) {
stop("CertificateManager functions require the openssl package to be installed.")
}
result <- new("CertificateManager")
result@location=as.character(NA)
result@obscuredpath=as.character(NA)
return(result)
})
#' Get DataONE Identity as Stored in the CILogon Certificate.
#' @description Returns Your Identity according to DataONE (and CILogon) as provided in the Subject
#' field of the X.509 certificate. The value is a Distinguished Name, and can be used in all fields that
#' require a user identity for access control authorization. If the certificate is missing on expired, then
#' the subject 'public' is returned.
#' @rdname showClientSubject
#' @aliases showClientSubject
#' @param x a CertificateManager instance
#' @param ... (Not yet used)
#' @return the DataONE Subject that is your client's identity
#' @export
setGeneric("showClientSubject", function(x, ...) {
.Deprecated("getCertInfo", "dataone")
standardGeneric("showClientSubject")
})
#' @rdname showClientSubject
setMethod("showClientSubject", signature("CertificateManager"), function(x) {
PUBLIC="public"
certfile <- getCertLocation(x)
if (!is.null(certfile)) {
cert <- openssl::read_cert(file=certfile)
subject <- as.list(cert)$subject
} else {
subject=PUBLIC
}
## since there's a certificate, now check to see if its expired, and if so, return PUBLIC
if (isCertExpired(x)) {
return(PUBLIC)
}
return(subject)
})
#' Determine if an X.509 certificate has expired.
#' @description Returns \code{'TRUE'} if the certificate associated with a CertificateManager instance is expired.
#' A certificate is expired if any of the following conditions hold: 1) the current time is before or after the
#' certificate validity dates, 2) the certificate is not valid according to a trusted Certificate Authority, or
#' 3) no certificate can be found.
#' @param x a CertificateManager instance
#' @param ... (Not yet used)
#' @rdname isCertExpired
#' @aliases isCertExpired
#' @return TRUE if the certificate is expired
#' @export
setGeneric("isCertExpired", function(x, ...) {
.Deprecated("getCertInfo", "dataone")
standardGeneric("isCertExpired")
})
#' @rdname isCertExpired
setMethod("isCertExpired", signature("CertificateManager"), function(x) {
expires <- getCertExpires(x)
if (is.null(expires)) {
return(TRUE)
} else {
now <- Sys.time()
if (expires < now) {
return(TRUE)
} else {
return(FALSE)
}
}
})
#' Show the date and time when an X.509 certificate expires.
#' @description Each X.509 has a range of certificate validity times. This method returns the X.509
#' \code{'notAfter'} field formatted as a \code{'POSIXct'} date value.
#' @param x a CertificateManager instance
#' @param ... (Not yet used)
#' @rdname getCertExpires
#' @aliases getCertExpires
#' @return POSIXct value
#' @export
setGeneric("getCertExpires", function(x, ...) {
.Deprecated("getCertInfo", "dataone")
standardGeneric("getCertExpires")
})
#' @rdname getCertExpires
setMethod("getCertExpires", signature("CertificateManager"), function(x) {
certfile <- getCertLocation(x)
if (!is.null(certfile)) {
cert <- openssl::read_cert(file=certfile)
expires <- as.POSIXct(as.list(cert)$validity[[2]], format="%b %d %H:%M:%S %Y", tz="GMT")
} else {
expires=NULL
}
return(expires)
})
#' Open the CILogon Certificate download page in the default browser.
#' @description A convenience method to take you to the CILogon download page:
#' "https://cilogon.org/?skin=DataONE. Logging into CILogon will allow
#' you to download your X.509 certificate to your local computer. Typically,
#' the certificate is saved in the default Globus location for certificates
#' (\code{\link{getCertLocation}}) and once it is there, the \code{'dataone'}
#' package will use the certificate for all authenticated operations. Deleting
#' the certificate file is the equivalent of logging out.
#' @param x a CertificateManager instance
#' @param ... (Not yet used)
#' @rdname downloadCert
#' @aliases downloadCert
#' @return NULL
#' @export
#' @importFrom utils browseURL
setGeneric("downloadCert", function(x, ...) {
standardGeneric("downloadCert")
})
#' @rdname downloadCert
setMethod("downloadCert", signature("CertificateManager"), function(x) {
browseURL("https://cilogon.org/?skin=DataONE")
})
#' Obscure the CILogon Client Certificate
#' @description Obscures the x509 certificate that CILogon installs, effectively making future
#' interactions with the DataONE services public/anonymous. This function simple renames an
#' existing certificate file to a known location, allowing 'public' operations. Note, when the
#' client certificate is obscured via the renaming, you will not be able to create objects in
#' DataONE, or utilize any other methods that require authentication.
#' @param x a CertificateManager instance
#' @param ... (Not yet used)
#' @rdname obscureCert
#' @aliases obscureCert
#' @return the modified CertificateManager instance
#' @seealso \code{\link{restoreCert}} is this method's inverse operation
#' @export
setGeneric("obscureCert", function(x, ...) {
.Deprecated("obscureAuth", "dataone")
standardGeneric("obscureCert")
})
#' @rdname obscureCert
setMethod("obscureCert", signature("CertificateManager"), function(x) {
certpath <- getCertLocation(x)
if (!is.null(certpath)) {
x@obscuredpath <- paste0(certpath, "_obscured")
file.rename(certpath, x@obscuredpath)
}
return(x)
})
#' Restore the CILogon client certificate by renaming it to its original location
#' @description Restores the x509 certificate that CILogon installs, which allows future
#' interactions with nodes to be authenticated with the certificate. This function simply
#' renames an obscured certificate file to its original location, allowing authenticated
#' operations.
#' @param x a CertificateManager instance
#' @param ... (Not yet used)
#' @rdname restoreCert
#' @aliases restoreCert
#' @return the modified CertificateManager instance
#' @seealso \code{\link{obscureCert}} is this method's inverse operation
#' @import stringr
#' @export
setGeneric("restoreCert", function(x, ...) {
.Deprecated("restoreAuth", "dataone")
standardGeneric("restoreCert")
})
#' @rdname restoreCert
setMethod("restoreCert", signature("CertificateManager"), function(x) {
certpath <- getCertLocation(x)
if (!is.null(certpath)) {
## if we got here, a new certificate is in the default location, so
## remove any obscured certificate
if (!is.na(x@obscuredpath)) {
file.remove(x@obscuredpath)
x@obscuredpath = as.character(NA)
}
} else {
expectedLoc <- str_sub(x@obscuredpath, end=(str_locate(x@obscuredpath, "_obscured")[[1]]-1))
# message("expected:",expectedLoc," obscured: ", x@obscuredpath)
if (file.exists(x@obscuredpath)) {
file.rename(x@obscuredpath, expectedLoc)
} else {
message("No obscured certificate to restore at ", x@obscuredpath)
}
x@obscuredpath <- as.character(NA)
}
return(x)
})
#' Get the file path on disk of the client certificate file.
#' @description Find the location of the client certificate, which is typically in a default
#' location on disk, unless the \code{'location'} slot has been set with a custom location for
#' the certificate.
#' @details The default Globus Grid Security Infrastructure (GSI) location is \code{'/tmp/x509up_u${UID}'}
#' on Unix or \code{'${tmpdir}/x509up_u${UID}'} on Windows or \code{'${tmpdir}/x509up_u${user.name}'}
#' if \code{'${UID}'} is not defined.
#' @param x a CertificateManager instance
#' @param ... (Not yet used)
#' @rdname getCertLocation
#' @aliases getCertLocation
#' @return character the path to the certificate
#' @export
setGeneric("getCertLocation", function(x, ...) {
.Deprecated("getCertInfo", "dataone")
standardGeneric("getCertLocation")
})
#' @rdname getCertLocation
setMethod("getCertLocation", signature("CertificateManager"), function(x) {
# default Globus Grid Security Infrastructure (GSI) location, which is /tmp/x509up_u${UID} on Unix
# or ${tmpdir}/x509up_u${UID} on Windows or ${tmpdir}/x509up_u${user.name} if ${UID} is not defined
# If a custom location is set, then just return that
if (!is.na(x@location)) {
return(x@location)
}
# Temp directory locations to check
loclist <- list('/tmp', Sys.getenv('TMPDIR', names=FALSE), Sys.getenv('TEMP', names=FALSE))
# Find the user's UID
# On windows, construct the same certificate filename as the GridShib-CA Logon Client
# that created/downloaded the certificate.
if(Sys.info()[['sysname']] == "Windows") {
uid <- Sys.info()['user']
certFnBase <- "\\x509up_u_"
} else {
uid <- as.numeric(system('id -u', intern=TRUE))
certFnBase <- "/x509up_u"
}
# If UID is null or not a number, try the username
if (is.null(uid)) {
uid <- Sys.info()['user']
}
# Our default is to return NULL if a cert file is not found
location <- NULL
counter <- 0
# Check each file path in order to see if the cert file exists, and if so, return it
for(counter in 1:length(loclist)) {
# Construct the default path to the filename
certpath <- paste(loclist[[counter]], certFnBase, uid, sep="")
# Check if the file exists
if (file.exists(certpath)) {
location <- certpath
break
}
}
# No file exists in the default locations, so return NULL
return(location)
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.