@@ -806,6 +806,106 @@ TEST_F(KeycacheTest, RefreshExpiredTest) {
806806 EXPECT_EQ (jwks_str, " {\" keys\" : []}" );
807807}
808808
809+ class IssuerSecurityTest : public ::testing::Test {
810+ protected:
811+ void SetUp () override {
812+ char *err_msg = nullptr ;
813+ m_key = KeyPtr (
814+ scitoken_key_create (" 1" , " ES256" , ec_public, ec_private, &err_msg),
815+ scitoken_key_destroy);
816+ ASSERT_TRUE (m_key.get () != nullptr ) << err_msg;
817+
818+ m_token = TokenPtr (scitoken_create (m_key.get ()), scitoken_destroy);
819+ ASSERT_TRUE (m_token.get () != nullptr );
820+
821+ // Store public key for verification
822+ auto rv = scitoken_store_public_ec_key (
823+ " https://demo.scitokens.org/gtest" , " 1" , ec_public, &err_msg);
824+ ASSERT_TRUE (rv == 0 ) << err_msg;
825+
826+ scitoken_set_lifetime (m_token.get (), 60 );
827+
828+ m_read_token.reset (scitoken_create (nullptr ));
829+ ASSERT_TRUE (m_read_token.get () != nullptr );
830+ }
831+
832+ using KeyPtr = std::unique_ptr<void , decltype (&scitoken_key_destroy)>;
833+ KeyPtr m_key{nullptr , scitoken_key_destroy};
834+
835+ using TokenPtr = std::unique_ptr<void , decltype (&scitoken_destroy)>;
836+ TokenPtr m_token{nullptr , scitoken_destroy};
837+
838+ TokenPtr m_read_token{nullptr , scitoken_destroy};
839+ };
840+
841+ TEST_F (IssuerSecurityTest, LongIssuerTruncation) {
842+ char *err_msg = nullptr ;
843+
844+ // Create a very long issuer (1000 characters)
845+ std::string very_long_issuer (1000 , ' A' );
846+ auto rv = scitoken_set_claim_string (m_token.get (), " iss" ,
847+ very_long_issuer.c_str (), &err_msg);
848+ ASSERT_TRUE (rv == 0 ) << err_msg;
849+
850+ char *token_value = nullptr ;
851+ rv = scitoken_serialize (m_token.get (), &token_value, &err_msg);
852+ ASSERT_TRUE (rv == 0 ) << err_msg;
853+ std::unique_ptr<char , decltype (&free)> token_value_ptr (token_value, free);
854+
855+ // Try to verify with a restricted issuer list to trigger error
856+ const char *allowed_issuers[] = {" https://good.issuer.com" , nullptr };
857+ rv = scitoken_deserialize_v2 (token_value, m_read_token.get (),
858+ allowed_issuers, &err_msg);
859+
860+ // Should fail
861+ ASSERT_FALSE (rv == 0 );
862+ ASSERT_TRUE (err_msg != nullptr );
863+ std::string error_message (err_msg);
864+ std::unique_ptr<char , decltype (&free)> err_msg_ptr (err_msg, free);
865+ // Error message should be reasonable length (< 400 chars)
866+ EXPECT_LT (error_message.length (), 400 );
867+ // Should contain expected error text
868+ EXPECT_NE (error_message.find (" is not in list of allowed issuers" ),
869+ std::string::npos);
870+
871+ // Should contain truncated issuer with ellipsis
872+ EXPECT_NE (error_message.find (" ..." ), std::string::npos);
873+ }
874+
875+ TEST_F (IssuerSecurityTest, SpecialCharacterIssuer) {
876+ char *err_msg = nullptr ;
877+
878+ // Create an issuer with special characters and control chars
879+ std::string special_issuer = " https://bad.com/\"\n\t\r\x01\x1f " ;
880+ auto rv = scitoken_set_claim_string (m_token.get (), " iss" ,
881+ special_issuer.c_str (), &err_msg);
882+ ASSERT_TRUE (rv == 0 ) << err_msg;
883+
884+ char *token_value = nullptr ;
885+ rv = scitoken_serialize (m_token.get (), &token_value, &err_msg);
886+ ASSERT_TRUE (rv == 0 ) << err_msg;
887+ std::unique_ptr<char , decltype (&free)> token_value_ptr (token_value, free);
888+
889+ // Try to verify with a restricted issuer list to trigger error
890+ const char *allowed_issuers[] = {" https://good.issuer.com" , nullptr };
891+ rv = scitoken_deserialize_v2 (token_value, m_read_token.get (),
892+ allowed_issuers, &err_msg);
893+
894+ // Should fail
895+ ASSERT_FALSE (rv == 0 );
896+ ASSERT_TRUE (err_msg != nullptr );
897+ std::string error_message (err_msg);
898+ std::unique_ptr<char , decltype (&free)> err_msg_ptr (err_msg, free);
899+ // Error message should be reasonable length
900+ EXPECT_LT (error_message.length (), 300 );
901+ // Should contain expected error text
902+ EXPECT_NE (error_message.find (" is not in list of allowed issuers" ),
903+ std::string::npos);
904+
905+ // Should contain properly escaped JSON (with quotes)
906+ EXPECT_NE (error_message.find (" \" " ), std::string::npos);
907+ }
908+
809909int main (int argc, char **argv) {
810910 ::testing::InitGoogleTest (&argc, argv);
811911 return RUN_ALL_TESTS ();
0 commit comments