web-dev-qa-db-ja.com

パスワードで保護されたPDFファイルをiTextSharpで開く

パスワード付きのPDFを表示するアプリケーションを作成しています。これは私のコードです:

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        try
        {
            string filePath = Request.QueryString["filePath"];
            if (filePath.ToUpper().EndsWith("PDF"))
            {
                copyPDF(filePath);
            }
        }
        catch
        {
            string message = "<script language='Javascript'>alert('File Not Found! Call Records Department for verification. ')</script>";
            ScriptManager.RegisterStartupScript(Page, this.GetType(), message, message, false);
        }
    }
}
public void copyPDF(string filePath)
{
    iTextSharp.text.pdf.RandomAccessFileOrArray ra = new iTextSharp.text.pdf.RandomAccessFileOrArray(Server.MapPath(ResolveUrl(filePath)));
    if (ra != null)
    {
        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        byte[] password = System.Text.ASCIIEncoding.ASCII.GetBytes("Secretinfo");
        iTextSharp.text.pdf.PdfReader thepdfReader = new iTextSharp.text.pdf.PdfReader(ra, password);
        int pages = thepdfReader.NumberOfPages;
        iTextSharp.text.Document pdfDoc = new iTextSharp.text.Document();
        iTextSharp.text.pdf.PdfCopy pdfCopy = new iTextSharp.text.pdf.PdfCopy(pdfDoc, ms);

        pdfDoc.Open();
        int i = 0;
        while (i < pages)
        {
            pdfCopy.AddPage(pdfCopy.GetImportedPage(thepdfReader, i + 1));
            i += 1;
        }
        pdfDoc.Close();
        Byte[] byteInfo = ms.ToArray();
        Response.Clear();
        Response.ContentType = "application/pdf";
        Response.AddHeader("content-length", byteInfo.Length.ToString());
        Response.BinaryWrite(byteInfo);
        Response.Flush();
        Response.End();
    }
}

私のコードはパスワードなしでPDFファイルを開くのに問題はありませんが、パスワードが提供されていてもパスワード付きのPDFを開くことはできません。アプリケーションは代わりにcatchを実行します。私のコードの何が問題になっているようですか?

[〜#〜] edit [〜#〜]Catchを削除して、スローされた例外を確認しました。

例外の詳細:System.ArgumentException:PdfReaderが所有者のパスワードで開かれていません

エラーの原因は51行目であると書かれています。

Line 49:    while (i < pages)
Line 50:    {
Line 51:         pdfCopy.AddPage(pdfCopy.GetImportedPage(thepdfReader, i + 1));
Line 52:         i += 1;
Line 53:    }
13
Artemis

暗号化されたドキュメントに対する特定の操作では、iText(Sharp)は、ドキュメントをユーザーパスワードだけでなく、所有者パスワードで開く必要があります。これは、PDF仕様のこれらのパスワードの定義に対応しています:

復号化されたドキュメントで追加の操作を許可するかどうかは、ドキュメントを開いたときに指定したパスワード(存在する場合)と、ドキュメントの作成時に指定したアクセス制限によって異なります。

  • 正しいownerパスワードでドキュメントを開くと、ドキュメントへの完全な(所有者)アクセスが許可されます。この無制限のアクセスには、ドキュメントのパスワードとアクセス許可を変更する機能が含まれています。
  • 正しいserパスワードでドキュメントを開く(またはデフォルトのパスワードでドキュメントを開く)と、ドキュメントの暗号化辞書で指定されているユーザーアクセス許可に従って追加の操作を実行できるようになります。

(セクション7.6.3.1 in ISO 32000-1

iText(Sharp)は現在詳細をチェックしていませんドキュメントの暗号化辞書で指定されたユーザーアクセス許可代わりに、特定の許可を必要とする操作には常に所有者パスワードが必要であり、ドキュメントからページ全体を確実にコピーすることは1つですそのうちの。

とはいえ、iText(Sharp)開発者は非常によく知っています(そのような質問がたくさんあるため)

  • iText(Sharp)ユーザーは、前述の理由により、所有者パスワードがなくてもそのような操作を実行する資格がある場合がありますドキュメントの暗号化辞書で指定されたユーザーアクセス許可
  • それぞれの所有者が所有者パスワードを適用して(他人による誤用を防ぐために)それを忘れた(またはランダムに生成されたものを使用することによって)最初から知らなかったPDFが無数にあること。
  • そのiText(Sharp)(オープンソースである)は、ユーザーと所有者のパスワードの違いを尊重しないように、誰でも簡単にパッチを当てることができます。

ユーザーが資格のあることを実行できるようにし、パッチが適用されたライブラリのコピーが広がらないようにするために、iText(Sharp)にはこのテストのオーバーライドがPdfReaderクラスに含まれています。

/**
 * The iText developers are not responsible if you decide to change the
 * value of this static parameter.
 * @since 5.0.2
 */
public static bool unethicalreading = false;

したがって、設定することによって

PdfReader.unethicalreading = true;

この権限チェックメカニズムをグローバルにオーバーライドします。

PDF作成者の権利を尊重し、問題の操作を実行する資格がある場合にのみこのオーバーライドを使用してください。

19
mkl

私はこの回避策を適用しました、そしてそれは働きます:

private void fixIssue(PdfReader pdfReader) throws Exception {
        Field f = pdfReader.getClass().getDeclaredField("ownerPasswordUsed");
        f.setAccessible(true);
        f.setBoolean(pdfReader, true);

}
1
Enrico Giurin