diff --git a/.coverage b/.coverage new file mode 100644 index 0000000..8e92d5b --- /dev/null +++ b/.coverage @@ -0,0 +1 @@ +!coverage.py: This is a private format, don't read it directly!{"lines":{"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_01_service_context.py":[1,2,4,5,6,8,11,28,34,40,51,80,81,91,106,124,147,213,233,247,13,14,15,16,18,19,20,21,22,23,25,29,30,31,35,36,37,42,43,44,46,47,48,84,85,86,87,89,92,93,94,95,96,97,98,99,102,103,107,108,109,110,111,112,113,114,115,118,120,121,122,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,143,144,145,148,149,150,152,153,154,155,156,157,158,160,162,163,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,196,197,198,201,71,72,74,75,203,77,206,210,214,215,216,217,218,219,220,223,224,225,226,227,228,229,231,236,238,239,241,242,245,248,251,253,255,256,257,258,259,260,261,264],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/__init__.py":[1,2,5,6,7,8,11,12,15,17,18,19,23,24,25,26,27,29,31,32,35,46,49,61,42,43,58],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/service_context.py":[4,5,6,7,9,10,11,12,13,16,17,21,22,23,26,27,28,31,32,33,39,40,41,44,45,46,49,50,51,54,59,60,61,62,63,64,65,69,81,87,89,154,157,179,202,227,244,265,268,274,90,91,92,94,97,99,101,104,105,106,107,108,109,110,111,113,115,117,122,269,272,124,125,126,127,129,132,133,134,135,136,138,139,140,141,142,144,149,150,151,152,118,119,120,146,266,170,173,174,175,234,235,236,237,238,239,240,242,251,252,253,254,261,263,187,188,189,192,194,197,199,200,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,130,275,177,190,191,195,270],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_03_util.py":[1,2,4,6,7,9,12,30,46,62,78,13,14,15,16,18,19,20,21,23,24,25,26,33,34,37,38,40,42,43,49,50,53,54,56,58,59,65,66,69,70,72,74,75,79,80,81,82,84,85,86,87,89,90,91,92],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/util.py":[1,2,3,4,6,7,9,11,13,14,15,18,44,67,74,89,28,29,30,31,32,35,36,37,54,55,57,58,33,91,76,82,83,86,92,93,41,39],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_07_service.py":[1,2,5,6,7,10,12,13,14,18,19,25,26,29,30,38,44,50,58,68,69,74,32,33,34,35,36,39,40,41,42,45,46,47,48,51,52,53,54,55,56,59,60,61,62,63,64,65,71,72,75,76,77,78],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/service.py":[1,2,3,5,6,7,9,10,11,12,13,16,18,20,22,24,27,28,29,30,31,32,33,34,35,36,37,38,39,42,66,107,123,143,158,167,204,226,242,253,275,285,355,373,384,404,413,435,507,523,539,43,45,46,50,51,52,60,63,64,177,183,184,133,115,116,117,118,121,134,135,141,188,194,75,83,84,87,88,89,90,91,94,95,96,97,98,99,100,101,102,103,105,199,201,151,153,156,85,306,307,308,309,282,310,311,313,237,240,314,315,317,318,323,324,325,263,265,273,328,329,330,331,248,249,333,336,348,351,364,365,367,368,371,551,552,553,554,555,556,558,559,560,563,564,48,568,570,573,574,578,178,136,137,190,191,92,455,458,460,471,472,474,478,480,414,415,416,433,482,485,488,489,490,493,499,501,505,382,154,266,267,216,217,219,220,221,222,268,269,338,339,345,346,349,238,53,54,57,58,270,271,319,456,494,495,496,497,475,405,406,407,408,409,410,411,476,340,343,392,393,394,395,398,402,566,517,520,399,165,251],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/client_auth.py":[1,2,3,4,6,7,8,9,10,11,13,15,17,20,21,24,25,29,49,53,55,59,68,79,81,92,100,117,147,163,188,196,198,220,234,271,272,274,312,313,314,333,349,367,371,373,391,403,424,443,462,481,515,531,538,540,543,547,550,552,555,561,562,563,564,565,566,569,572,588,173,174,176,177,179,111,83,84,90,112,94,95,98,114,115,181,183,155,156,157,158,161,126,135,136,137,138,141,142,143,144,145,185,85,86,87,96,97,127,128,129,130,131,132,287,290,249,250,251,255,257,258,292,297,300,301,302,309,304,305,306,307,252,253,260,261,262,265,266,267,268,344,322,323,324,325,326,328,331,346,230,207,208,218,231,209,210,526,489,496,500,463,465,444,448,449,450,452,453,454,458,459,553,382,383,387,389,460,467,470,425,426,427,429,436,556,441,472,473,474,475,479,40,42,43,44,45,46,501,503,504,505,506,509,510,511,512,513,528,490,491,495,541,544,456,581,582,583,585,584,593,594,288,88,89],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/exception.py":[2,6,7,12,13,16,17,20,21,24,25,28,29,32,33,36,37,40,41,44,45,48,49,52,53,56,57,60,64,66,71,72,75,76,79,80,83,84,87,88,91,92,95,96,99,100,103,104,107,108,111,112,115,116,8,9],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/state_interface.py":[1,2,4,6,8,11,12,14,15,16,17,18,19,20,25,26,27,28,32,33,34,37,41,48,55,59,66,74,75,76,79,92,114,126,144,186,227,249,264,274,285,296,307,318,329,340,351,369,35,39,77,163,164,137,86,87,88,165,166,183,358,359,365,366,367,102,103,90,107,108,112,109,110,202,204,205,206,210,211,217,218,219,220,221,222,223,207,208,225,104,105,138,139,168,169,175,176,177,178,179,180,181,140,361,272,236,237,238,242,243,247,283,258,259,260,338,245,246,212,213,294,141],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_08_webfinger.py":[1,2,4,5,6,8,9,10,12,14,17,52,120,133,148,157,180,223,245,246,256,266,277,289,301,18,19,21,22,23,24,25,26,27,28,29,30,31,32,34,36,37,38,39,42,43,44,45,46,47,48,49,53,54,58,60,62,63,65,67,69,71,72,74,75,77,78,80,81,83,84,86,87,89,90,93,94,97,98,101,102,105,106,110,111,112,113,114,115,116,117,121,122,123,124,127,128,129,130,134,135,137,138,141,142,143,144,145,149,150,152,153,154,158,159,161,164,167,168,169,170,172,173,174,177,182,184,187,191,192,193,196,197,200,201,202,204,205,209,210,215,217,218,219,220,225,227,230,232,235,236,237,241,242,247,248,249,250,251,252,253,254,257,258,259,260,261,262,263,264,267,268,269,271,272,273,274,275,278,279,280,281,283,284,285,286,287,290,291,292,293,295,296,297,298,299,302,303,304,307,309,310],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/__init__.py":[5,9,12,15,18,21,25,26,29,30,31,35,36,37,38,39],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/webfinger.py":[1,2,4,5,6,7,9,10,12,14,16,17,18,19,20,23,26,27,28,29,30,31,32,33,36,42,65,75,147,37,38,40,83,86,87,91,92,93,94,95,100,103,104,143,144,145,101,96,97,98,116,117,124,127,140,141,67,68,69,72,70,73,128,129,130,132,133,137,138,105,106,107,108,110,111,112,120,121,122,123,149,152,153,163,154,155,156,157,158,159,160,161,43,44,48,49,50,51,52,53,54,55,57,61,62,63],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_09_client_auth.py":[1,2,3,5,6,7,8,9,10,11,15,16,20,21,22,23,24,26,27,29,30,31,32,35,39,45,53,65,77,78,91,100,110,111,118,128,139,148,178,179,187,206,228,229,249,250,279,296,297,329,330,362,363,66,67,68,69,70,72,55,56,57,58,59,60,61,62,40,42,79,80,82,83,85,86,87,92,93,95,96,98,102,104,105,107,112,113,114,46,48,49,50,116,119,120,122,123,125,36,126,129,131,132,133,135,136,137,140,141,143,145,146,149,150,151,152,153,154,157,158,159,160,163,164,165,166,167,169,173,174,175,180,181,182,184,185,188,189,191,192,194,195,196,197,198,199,201,202,203,204,207,208,209,210,211,212,214,215,216,217,218,219,221,222,224,225,230,231,232,233,234,236,237,238,240,241,242,243,244,245,246,251,252,253,255,256,258,259,260,261,262,264,265,266,267,268,269,271,272,273,274,276,280,282,283,285,286,287,288,289,290,291,292,293,298,299,300,301,302,304,305,307,308,309,310,311,313,314,315,316,317,318,320,321,322,324,325,331,332,333,334,335,337,338,340,341,342,343,344,346,347,348,349,350,351,353,354,355,356,358,359,364,365,368,369,370,372,373,375,376,379,380],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/service_factory.py":[1,2,3,4,6,9,33,10,11,12,14,15,16,17,18,20,21,22,24,25,26,27,28,19],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_10_oauth2_service.py":[1,2,6,7,8,9,12,13,19,25,26,38,51,65,79,80,98,107,119,140,160,161,186,191,198,199,216,223,228,20,21,22,29,30,31,32,34,35,36,39,40,41,42,43,44,45,46,52,53,54,55,56,57,58,59,66,67,68,69,70,71,72,83,84,85,87,88,89,90,91,92,94,95,96,99,101,102,103,110,112,113,114,115,121,122,124,125,126,127,128,129,130,131,132,133,138,142,143,145,147,148,149,150,151,152,153,163,166,167,170,171,172,173,174,175,177,178,180,181,182,183,184,187,188,189,192,193,194,202,203,204,206,207,208,209,210,211,212,213,214,217,218,219,220,224,225,230,231,232,234,235,236,237,239,240,241,242,243,246,247,249,250,251,253,254,255,256],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_13_oic_service.py":[1,2,4,5,6,7,8,9,10,13,15,18,19,21,22,25,26,33,34,37,39,41,42,43,45,46,47,49,50,52,53,62,63,74,85,97,107,118,128,138,158,174,181,198,219,237,257,258,272,284,296,309,310,327,337,356,375,384,385,407,412,418,520,550,564,573,574,586,591,599,609,610,646,652,659,688,716,725,746,747,760,769,770,783,791,792,806,816,844,861,880,899,66,67,69,70,71,72,76,77,79,80,81,87,88,90,91,92,95,99,100,102,103,104,109,110,112,113,114,116,119,120,121,122,123,124,125,129,130,131,132,133,134,135,139,140,141,142,143,144,145,146,148,149,150,151,152,153,154,155,159,160,162,164,165,166,168,169,170,172,175,176,177,178,179,182,183,184,186,187,189,190,191,193,194,195,196,199,200,201,203,205,206,209,210,211,213,214,215,216,217,220,221,222,224,225,227,228,229,231,232,233,234,235,239,240,241,243,244,245,247,249,250,251,253,254,261,263,264,265,268,269,270,274,275,277,278,279,282,286,287,289,290,291,294,298,299,301,302,303,306,313,314,316,317,319,320,321,322,324,325,328,330,331,332,333,339,340,342,343,344,345,346,347,348,349,350,358,359,361,363,364,365,366,367,368,369,376,377,378,379,380,381,387,389,390,391,394,395,396,397,398,399,400,403,404,405,408,409,410,413,414,415,419,422,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,458,459,460,461,463,464,465,466,468,469,470,472,473,474,476,477,478,479,481,482,483,484,486,487,488,490,491,493,494,496,497,498,499,500,501,502,503,504,505,506,508,509,510,511,521,524,526,527,528,529,530,531,532,533,534,535,537,538,539,540,551,552,554,555,558,559,576,578,579,580,581,583,584,587,588,589,593,594,595,596,597,600,601,602,603,604,605,606,612,614,615,616,617,619,620,621,622,623,624,627,630,631,634,635,637,565,567,569,570,639,641,642,643,644,647,648,649,650,653,654,655,656,657,662,663,664,665,666,668,671,672,674,675,677,678,680,682,683,684,691,692,693,694,695,697,700,702,703,705,706,708,709,711,713,714,717,718,719,720,721,722,723,727,729,730,732,734,735,736,737,738,740,741,742,743,749,751,752,753,754,756,757,758,761,762,763,764,765,766,772,774,775,776,777,779,780,781,784,785,786,787,788,794,796,797,798,799,800,802,803,804,807,808,809,810,811,812,818,819,820,821,824,825,826,828,829,830,832,833,839,840,841,846,847,848,849,851,852,855,856,857,858,863,864,865,866,867,869,870,873,874,875,876,877,882,883,884,886,887,890,891,892,894,895,896,901,902,903,905,906,909,910,911,912,913],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/registration.py":[1,3,4,6,7,9,11,15,16,17,18,19,20,24,41,53,71,96,97,98,99,100,101,102,103,104,106,115,130,143,107,108,109,110,111,112,113,25,27,28,29,30,31,36,38,116,117,120,121,122,123,125,126,127,128,42,43,44,45,50,63,64,65,68,72,76,79,80,81,85,86,87,88,93,131,132,133,138,141,66,46,47,48,90,91,82,83,73,75,144,147,148,149,150,151,152,153,154,156,157,158,159,160,161,162,163,167,168,169,139],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/provider_info_discovery.py":[1,3,4,6,7,9,11,15,17,19,20,22,24,25,27,29,30,31,32,34,35,36,37,40,43,44,48,72,73,74,75,77,82,91,78,79,80,83,84,105,108,110,112,113,114,115,116,118,119,131,132,133,156,135,136,144,145,146,147,148,149,137,139,140,159,160,163,164,165,167,171,172,169,170,166,161,174,175,85,120,121,124,125,126,127,128,129,57,58,61,62,67,69],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oauth2/__init__.py":[5,8,11,14],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oauth2/provider_info_discovery.py":[1,2,4,5,6,8,9,10,12,15,16,17,18,19,20,21,22,24,28,44,54,78,88,105,143,25,26,52,34,35,39,42,116,117,118,55,56,62,65,69,70,71,72,76,122,123,125,92,93,94,95,129,130,136,137,141,97,98,102,103,80,84,85,86],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_14_pkce.py":[1,3,4,5,6,8,9,10,11,12,13,14,17,19,23,24,27,29,32,33,36,37,38,41,42,71,85,95,109,110,138,45,46,47,49,50,52,53,58,59,60,61,62,64,66,67,69,72,73,74,75,78,80,82,83,86,87,88,90,91,96,97,98,99,100,102,103,104,113,114,116,117,119,120,125,126,127,128,129,131,133,134,136,139,140,141,143,145,146],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/add_on/__init__.py":[1,4,5,6,7],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/add_on/pkce.py":[1,3,4,6,7,8,10,13,62,80,85,95,96,98,99,102,104,105,106,24,26,27,32,33,35,36,40,42,44,46,51,52,54,56,57,59,72,73,74,75,76,77,81,82],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oauth2/utils.py":[1,4,17,49,6,7,14,19,21,24,25,44,46,51,52,8,9,10,26,27,32,33,34,35,37,39,40,42,38],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_15_oic_utils.py":[1,2,3,5,7,10,11,14,16,19,43,20,21,22,25,26,27,29,30,31,32,33,35,36,38,40,44,45,46,47,48,49],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/utils.py":[1,3,4,5,7,10,68,19,20,21,22,23,24,25,26,28,31,32,33,34,35,36,41,45,46,48,49,50,51,53,56,62,63,65,78,79,81,82,83,84,87,88],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_16_cc_oauth2_service.py":[1,3,4,5,7,10,11,30,42,14,15,17,19,20,21,22,23,24,25,27,28,31,32,33,34,35,36,37,43,44,45,46,47,48,49,51,52,53,54,55,57],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_17_read_registration.py":[1,2,4,5,6,7,9,10,11,13,14,17,18,41,20,22,23,24,26,27,28,29,30,31,32,35,36,37,38,39,42,44,46,48,49,50,51,52,53,54,55,56,57,58,59,60,63,64,65,66,67,68,69,72,73,75,77,78,79,80,81,82,83,84,85,88,89],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_20_conversation.py":[2,3,4,6,7,8,12,13,14,15,16,21,22,26,27,29,30,31,32,34,37,38,41,42,43,44,45,46,47,52,53,54,55,58,59,60,61,62,67,69,71,74,75,76,77,78,79,83,84,85,86,88,89,94,95,96,100,101,102,103,104,105,107,108,112,113,115,116,118,122,126,127,129,136,137,139,140,142,145,147,148,149,153,154,158,160,164,165,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,201,202,203,204,206,207,208,209,211,212,213,215,216,217,219,220,221,223,224,225,227,228,229,231,232,234,235,237,238,239,240,241,242,243,244,245,246,249,251,252,254,255,256,257,261,263,264,265,274,276,278,279,280,281,282,283,284,285,286,287,288,289,290,291,294,295,297,298,299,300,309,310,312,313,315,316,317,319,320,321,324,325,326,327,328,331,333,334,335,336,337,342,343,346,347,349,350,351,358,365,366,368,369,371,374,375,376,377,378,379,382,383,384,386,387,390,392,393,395,400,401,405,407,408,410,412,413,415,416,418,419,420],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_21_pushed_auth.py":[1,2,4,5,6,8,9,10,11,12,13,15,17,20,21,24,25,26,29,30,66,33,34,35,37,39,42,43,44,45,50,51,52,53,54,56,58,59,61,62,63,67,68,69,71,72,74,75,76,77,79,81],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/tests/test_30_persistence.py":[2,3,4,5,7,8,9,10,13,14,15,16,21,22,26,27,29,30,31,32,38,42,43,46,47,48,49,50,51,52,57,58,59,62,63,64,65,66,71,73,75,78,79,80,81,86,88,90,93,94,95,96,97,98,102,103,104,106,107,111,164,165,166,171,112,114,117,118,119,120,121,122,124,125,126,129,130,131,132,133,136,137,138,139,142,143,144,145,151,152,154,156,160,161,172,174,175,178,179,181,183,184,186,187,189,190,192,195,197,201,203,205,206,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,242,243,244,245,247,248,249,250,252,253,254,256,257,258,260,261,262,264,265,266,268,269,270,272,273,275,276,278,279,280,281,282,283,284,285,286,287,290,292,293,294,295,297,301,303,304,305,314,316,318,319,320,321,322,323,324,325,326,327,328,329,330,331,334,336,340,341,343,344,346,347,350,351,352,353,354,357,359,360,368,369,372,373,375,376,377,384,391,392,394,395,397,400,401,402,403,404,405,408,409,410,412,413,416,418,419,421,426,427,431,433,434,436,438,439,441,442,443,444],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/authorization.py":[1,3,4,5,7,8,9,10,11,12,15,17,20,21,22,23,25,32,45,65,107,124,142,169,198,26,27,28,29,30,204,206,207,208,211,219,220,221,222,224,225,226,229,46,47,48,49,61,63,33,34,35,36,37,41,42,43,66,69,70,76,77,83,84,85,87,90,91,92,93,94,98,105,177,178,179,180,182,186,187,188,189,195,196,78,79,99,102,103,191,193,144,108,109,110,111,112,113,117,118,119,120,121,122,145,147,148,150,151,152,153,154,155,156,158,161,162,164,165,100,167,131,132,133,137,138,139,140,53,54,59,55,56,57,227,38,39,71,72,73,212,213,214,215,216,217],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oauth2/authorization.py":[1,2,4,5,6,7,9,11,13,16,17,18,19,20,21,22,23,24,26,32,37,43,54,27,28,29,30,64,65,66,70,77,44,46,52,39,40,41],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/access_token.py":[1,3,4,5,7,8,9,11,13,16,17,18,19,22,26,61,81,23,24,32,36,37,38,41,49,50,51,52,54,55,56,59,62,63,64,65,75,76,77,79,82,83,84,85,86,67,68,69,70,42,43,44,45,46,47,73],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oauth2/access_token.py":[1,2,4,5,6,8,9,11,14,15,16,17,18,19,20,21,22,23,24,25,27,32,37,28,29,30,44,45,47,48,50,51,53,54,56,59,60,62],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/refresh_access_token.py":[1,3,6,7,8,9,11],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oauth2/refresh_access_token.py":[1,2,4,5,6,8,9,11,14,15,16,17,18,19,20,21,22,23,25,30,35,26,27,28,37,38,40,41,43,44,45,47,50,51,53],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/userinfo.py":[1,3,4,5,7,8,10,13,14,15,19,30,31,32,33,34,35,36,37,38,40,45,59,106,41,42,43,46,49,52,53,54,57,27,112,114,115,116,119,120,127,128,129,130,132,60,61,62,65,66,70,73,74,75,76,103,104,78,79,80,81,82,83,89,90,91,93,94,84,85,86,87,121,122,123,124,125],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/end_session.py":[1,3,4,6,7,9,11,14,15,16,17,18,19,20,21,23,30,53,65,24,25,26,27,28,38,39,40,41,44,45,49,51,54,55,58,59,63,66,67,70,72],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/read_registration.py":[1,3,4,5,7,9,12,13,14,15,16,17,18,19,21,27,37,39,40,41,42,43,46,22,23],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/check_id.py":[1,3,4,6,8,10,13,14,15,16,17,18,19,21,26,22,23,24,27,28,29,30],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/check_session.py":[1,3,4,6,8,10,13,14,15,16,17,18,19,21,26,22,23,24,27,28,29,30],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oauth2/client_credentials/__init__.py":[1],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oauth2/client_credentials/cc_access_token.py":[1,2,3,5,8,9,10,11,12,13,14,15,16,17,18,20,24,21,22,25,26,27],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oauth2/client_credentials/cc_refresh_access_token.py":[1,2,3,5,8,9,10,11,12,13,14,15,16,18,24,41,50,19,20,21,22,25,26,27,29,30,31,33,36,37,39,42,43,44,48],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/src/oidcservice/oidc/add_on/pushed_authorization.py":[1,3,4,5,7,9,12,54,62,63,65,67,68,69,70,73,19,22,25,26,27,29,30,31,32,34,37,38,39,42,43,44,45,46,47,48,50],"/home/wert/DEV3/OIDC-Project/JWTConnect-Python-OidcService/setup.py":[]}} \ No newline at end of file diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..abc2344 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,3 @@ +# .coveragerc to control coverage.py +[run] +source = . diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml new file mode 100644 index 0000000..2072009 --- /dev/null +++ b/.github/workflows/python-app.yml @@ -0,0 +1,56 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: oidcservice + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + python-version: + - '3.6' + - '3.7' + - '3.8' + - '3.9' + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install rustc and cargo + run: | + sudo apt-get install rustc + sudo apt install cargo + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -U wheel --user + pip install setuptools-rust + python setup.py install + python setup.py test + pip install flake8 + pip install pytest + pip install pytest-httpserver + pip install responses + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 ./src/oidcservice --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 ./src/oidcservice --count --exit-zero --statistics + + - name: Unit tests + run: | + py.test tests/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..eb54c0d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,34 @@ +sudo: false +language: python +python: +- 3.6 +- 3.7 +- 3.8 +- pypy3 +addons: + apt: + packages: + - +install: +- pip install codecov +- pip install tox +- pip install isort +- pip install tox-travis +- pip install responses +script: +- codecov --version +- tox +- isort --check src tests +after_success: +- codecov +notifications: + email: false +deploy: + provider: pypi + on: + tags: true + distributions: bdist_wheel + skip_existing: true + user: __token__ + password: + secure: AH3jGGXVjV/oOlg4cOnsN7pURlZ7JMcd3Prr69Q++rxfsrmFpxCPtQLpO0LUNPisfyctoImpY64auNMHh20AHdlnvXQu8k/YFZCVcyK6N2d66wgJbO9AOT21N6IkFGyW11K3lYIHzURv9RsTEhzSkOhKmPUack5UhSJ+yAUTZXpt6iZqXBvmxMNzNiCLQdUmTMj4HxxkUVPabpef8PLqyDXvAxJxOCss+QcJVZuWFs85Niw0scTkU4SWz2lhOxeqQNg8s+CEgje2KaIoRy2kETywK53G3RFkSp5ytIJPp8RQK039laeal5yjMsWP4KlbDhHrywyNN7yS69FwPuLC41ppde5G054WcuJTm60Y2uckGu6L3oTBMHsAtSfZuEym/qfDngxYADA+xrATJQF5XSrCz13IiBnoz8Y9zI7t9s66PZSBHg99L85jM45M2kJYCDKxNPffJ/JzCnAMTP0yiBMEQ/UfguMDfJMw+6oSPzGcZHuQVzjLO5mUni71X528Psd/iEYCyN+Vi1QbvDZjbNo/oOLtvegOcnu/H1tGWkH4uEXsg2giqkld2hrZi6K3KfcpPtltuP66Z6ohMqcLegqGUNr8mPMP2I58p7if/6xLEu1e7MNZuoV459bnWepoNMMug2NLq/WIPCiGLNCyV4tdbzqcZQLNwjc5ruFLoz8= diff --git a/Makefile b/Makefile index 7fdbcb2..58c789f 100755 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ SPHINXBUILD = sphinx-build SPHINXABUILD = sphinx-autobuild BUILDDIR = doc/_build DOCDIR = doc/ -OIDCDIR = src/oidcmsg +OIDCDIR = src/oidcservice TESTDIR = tests help: @@ -40,10 +40,10 @@ test: .PHONY: test isort: - @pipenv run isort --recursive $(OIDCDIR) $(TESTDIR) + @pipenv run isort $(OIDCDIR) $(TESTDIR) check-isort: - @pipenv run isort --recursive --diff --check-only $(OIDCDIR) $(TESTDIR) + @pipenv run isort --diff --check-only $(OIDCDIR) $(TESTDIR) .PHONY: isort check-isort check-pylama: diff --git a/README.md b/README.md index d11b3d7..928d0c9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +# Archived !! + +The functionality in this package has been included in the IdentityPython/JWTConnect-Python-OidcRP package. +This package is therefor redundant and has been archived. + # oidcservice #### Implementation of OIDC/OAuth2 services diff --git a/setup.py b/setup.py index afc36bf..896e528 100755 --- a/setup.py +++ b/setup.py @@ -23,19 +23,19 @@ __author__ = 'Roland Hedberg' -class PyTest(TestCommand): - def finalize_options(self): - TestCommand.finalize_options(self) - self.test_args = [] - self.test_suite = True - - def run_tests(self): - # import here, cause outside the eggs aren't loaded - import pytest - - errno = pytest.main(self.test_args) - sys.exit(errno) - +# class PyTest(TestCommand): +# def finalize_options(self): +# TestCommand.finalize_options(self) +# self.test_args = [] +# self.test_suite = True +# +# def run_tests(self): +# # import here, cause outside the eggs aren't loaded +# import pytest +# +# errno = pytest.main(self.test_args) +# sys.exit(errno) +# # Python 2.7 and later ship with importlib and argparse if sys.version_info[0] == 2 and sys.version_info[1] == 6: @@ -62,19 +62,20 @@ def run_tests(self): classifiers=[ "Development Status :: 4 - Beta", "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules"], install_requires=[ "pyyaml>=5.1.0", 'oidcmsg>=1.1.0', + 'requests' ], tests_require=[ "responses", "testfixtures", "pytest-localserver" ], - zip_safe=False, - cmdclass={'test': PyTest}, + zip_safe=False ) diff --git a/src/oidcservice/__init__.py b/src/oidcservice/__init__.py index 66ba53e..af7fd99 100755 --- a/src/oidcservice/__init__.py +++ b/src/oidcservice/__init__.py @@ -3,14 +3,12 @@ # Since SystemRandom is not available on all systems try: - import random.SystemRandom as rnd + import SystemRandom as rnd except ImportError: import random as rnd - __author__ = 'Roland Hedberg' -__version__ = '1.1.0' - +__version__ = '1.1.1' OIDCONF_PATTERN = "{}/.well-known/openid-configuration" CC_METHOD = { @@ -31,6 +29,8 @@ JWT_BEARER = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" SAML2_BEARER_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:saml2-bearer" +BASECHR = string.ascii_letters + string.digits + def rndstr(size=16): """ @@ -39,8 +39,7 @@ def rndstr(size=16): :param size: The length of the string :return: string """ - _basech = string.ascii_letters + string.digits - return "".join([rnd.choice(_basech) for _ in range(size)]) + return "".join([rnd.choice(BASECHR) for _ in range(size)]) BASECH = string.ascii_letters + string.digits + '-._~' diff --git a/src/oidcservice/client_auth.py b/src/oidcservice/client_auth.py index da210e9..bfadd4f 100755 --- a/src/oidcservice/client_auth.py +++ b/src/oidcservice/client_auth.py @@ -4,17 +4,14 @@ from urllib.parse import quote_plus from cryptojwt.exception import MissingKey +from cryptojwt.jws.jws import SIGNER_ALGS from cryptojwt.jws.utils import alg2keytype from oidcmsg.message import VREQUIRED -from oidcmsg.oauth2 import AccessTokenRequest -from oidcmsg.oauth2 import SINGLE_OPTIONAL_STRING +from oidcmsg.oauth2 import SINGLE_OPTIONAL_STRING, AccessTokenRequest from oidcmsg.oidc import AuthnToken from oidcmsg.time_util import utc_time_sans_frac -from oidcservice import DEF_SIGN_ALG -from oidcservice import JWT_BEARER -from oidcservice import rndstr -from oidcservice import sanitize +from oidcservice import DEF_SIGN_ALG, JWT_BEARER, rndstr, sanitize LOGGER = logging.getLogger(__name__) @@ -128,7 +125,7 @@ def _with_or_without_client_id(request, service): :param service: A :py:class:`oidcservice.service.Service` instance """ if isinstance(request, AccessTokenRequest) and request[ - 'grant_type'] == 'authorization_code': + 'grant_type'] == 'authorization_code': if 'client_id' not in request: try: request['client_id'] = service.service_context.get('client_id') @@ -315,6 +312,7 @@ def construct(self, request=None, service=None, http_args=None, class BearerBody(ClientAuthnMethod): """The bearer body authentication method.""" + def modify_request(self, request, service, **kwargs): """ Modify the request if necessary. @@ -450,11 +448,24 @@ def _get_audience_and_algorithm(self, context, **kwargs): # audience for the signed JWT depends on which endpoint # we're talking to. if 'authn_endpoint' in kwargs and kwargs['authn_endpoint'] in ['token_endpoint']: - try: - algorithm = context.behaviour[ - 'token_endpoint_auth_signing_alg'] - except (KeyError, AttributeError): - pass + reg_resp = context.get("registration_response") + if reg_resp: + algorithm = reg_resp.get("token_endpoint_auth_signing_alg") + else: + algorithm = context.client_preferences.get("token_endpoint_auth_signing_alg") + if algorithm is None: + _pi = context.get("provider_info") + try: + algs = _pi["token_endpoint_auth_signing_alg_values_supported"] + except KeyError: + algorithm = "RS256" # default + else: + for alg in algs: # pick the first one I support and have keys for + if alg in SIGNER_ALGS and self.get_signing_key_from_keyjar(alg, + context): + algorithm = alg + break + audience = context.get('provider_info')['token_endpoint'] else: audience = context.get('provider_info')['issuer'] diff --git a/src/oidcservice/oauth2/authorization.py b/src/oidcservice/oauth2/authorization.py index e154d44..c081502 100644 --- a/src/oidcservice/oauth2/authorization.py +++ b/src/oidcservice/oauth2/authorization.py @@ -6,12 +6,10 @@ from oidcmsg.oauth2 import ResponseMessage from oidcmsg.time_util import time_sans_frac -from oidcservice.oauth2.utils import get_state_parameter -from oidcservice.oauth2.utils import pick_redirect_uris -from oidcservice.oauth2.utils import set_state_parameter +from oidcservice.oauth2.utils import (get_state_parameter, pick_redirect_uris, + set_state_parameter) from oidcservice.service import Service - LOGGER = logging.getLogger(__name__) diff --git a/src/oidcservice/oauth2/provider_info_discovery.py b/src/oidcservice/oauth2/provider_info_discovery.py index 02105c2..ccdec11 100644 --- a/src/oidcservice/oauth2/provider_info_discovery.py +++ b/src/oidcservice/oauth2/provider_info_discovery.py @@ -2,7 +2,6 @@ import logging from cryptojwt.key_jar import KeyJar - from oidcmsg import oauth2 from oidcmsg.oauth2 import ResponseMessage diff --git a/src/oidcservice/oauth2/refresh_access_token.py b/src/oidcservice/oauth2/refresh_access_token.py index c58ac37..dae2bf3 100644 --- a/src/oidcservice/oauth2/refresh_access_token.py +++ b/src/oidcservice/oauth2/refresh_access_token.py @@ -8,7 +8,6 @@ from oidcservice.oauth2.utils import get_state_parameter from oidcservice.service import Service - LOGGER = logging.getLogger(__name__) diff --git a/src/oidcservice/oidc/access_token.py b/src/oidcservice/oidc/access_token.py index 174d095..7d2e128 100644 --- a/src/oidcservice/oidc/access_token.py +++ b/src/oidcservice/oidc/access_token.py @@ -4,8 +4,8 @@ from oidcmsg.oidc import verified_claim_name from oidcmsg.time_util import time_sans_frac -from oidcservice.oauth2 import access_token from oidcservice.exception import ParameterError +from oidcservice.oauth2 import access_token from oidcservice.oidc import IDT2REG __author__ = 'Roland Hedberg' diff --git a/src/oidcservice/oidc/add_on/pkce.py b/src/oidcservice/oidc/add_on/pkce.py index 2301975..fa86531 100644 --- a/src/oidcservice/oidc/add_on/pkce.py +++ b/src/oidcservice/oidc/add_on/pkce.py @@ -3,8 +3,7 @@ from cryptojwt.utils import b64e from oidcmsg.message import Message -from oidcservice import CC_METHOD -from oidcservice import unreserved +from oidcservice import CC_METHOD, unreserved from oidcservice.exception import Unsupported from oidcservice.oauth2.utils import get_state_parameter diff --git a/src/oidcservice/oidc/add_on/pushed_authorization.py b/src/oidcservice/oidc/add_on/pushed_authorization.py index a052ae5..779de1c 100644 --- a/src/oidcservice/oidc/add_on/pushed_authorization.py +++ b/src/oidcservice/oidc/add_on/pushed_authorization.py @@ -1,10 +1,11 @@ import logging -import requests from cryptojwt import JWT from oidcmsg.message import Message from oidcmsg.oauth2 import JWTSecuredAuthorizationRequest +import requests + logger = logging.getLogger(__name__) @@ -49,11 +50,14 @@ def push_authorization(request_args, service, **kwargs): return request_args -def add_pushed_authorization_support(services, body_format="jws", signing_algorthm="RS256", +def add_pushed_authorization_support(services, body_format="jws", signing_algorithm="RS256", http_client=None, merge_rule="strict"): """ Add the necessary pieces to make pushed authorization happen. + :param merge_rule: + :param http_client: + :param signing_algorithm: :param services: A dictionary with all the services the client has access to. :param body_format: jws or urlencoded """ @@ -64,7 +68,7 @@ def add_pushed_authorization_support(services, body_format="jws", signing_algort _service = services["authorization"] _service.service_context.add_on['pushed_authorization'] = { "body_format": body_format, - "signing_algorithm": signing_algorthm, + "signing_algorithm": signing_algorithm, "http_client": http_client, "merge_rule": merge_rule } diff --git a/src/oidcservice/oidc/authorization.py b/src/oidcservice/oidc/authorization.py index 4ae5a2a..b951f37 100644 --- a/src/oidcservice/oidc/authorization.py +++ b/src/oidcservice/oidc/authorization.py @@ -1,18 +1,16 @@ import logging from oidcmsg import oidc -from oidcmsg.oidc import make_openid_request -from oidcmsg.oidc import verified_claim_name -from oidcmsg.time_util import time_sans_frac -from oidcmsg.time_util import utc_time_sans_frac +from oidcmsg.oidc import make_openid_request, verified_claim_name +from oidcmsg.time_util import time_sans_frac, utc_time_sans_frac from oidcservice import rndstr from oidcservice.exception import ParameterError from oidcservice.oauth2 import authorization from oidcservice.oauth2.utils import pick_redirect_uris from oidcservice.oidc import IDT2REG -from oidcservice.oidc.utils import construct_request_uri -from oidcservice.oidc.utils import request_object_encryption +from oidcservice.oidc.utils import (construct_request_uri, + request_object_encryption) __author__ = 'Roland Hedberg' @@ -151,11 +149,12 @@ def construct_request_parameter(self, req, request_method, audience=None, expire kwargs["keys"] = self.service_context.keyjar _srv_cntx = self.service_context - kwargs['issuer'] = _srv_cntx.get('client_id') - # set the audience - if audience: - kwargs["recv"] = _srv_cntx.get('provider_info')[audience] - else: + + # This is the issuer of the JWT, that is me ! + if kwargs.get('issuer') is None: + kwargs['issuer'] = _srv_cntx.get('client_id') + + if kwargs.get('recv') is None: try: kwargs['recv'] = _srv_cntx.get('provider_info')['issuer'] except KeyError: @@ -214,11 +213,15 @@ def gather_verify_arguments(self): """ _ctx = self.service_context kwargs = { - 'client_id': _ctx.get('client_id'), 'iss': _ctx.get('issuer'), + 'iss': _ctx.get('issuer'), 'keyjar': _ctx.keyjar, 'verify': True, 'skew': _ctx.clock_skew } + _client_id = _ctx.get('client_id') + if _client_id: + kwargs['client_id'] = _client_id + if 'registration_response' in _ctx: _reg_res = _ctx.get('registration_response') for attr, param in IDT2REG.items(): diff --git a/src/oidcservice/oidc/check_id.py b/src/oidcservice/oidc/check_id.py index 4d3c2b8..a6f2847 100644 --- a/src/oidcservice/oidc/check_id.py +++ b/src/oidcservice/oidc/check_id.py @@ -1,7 +1,6 @@ import logging -from oidcmsg.oauth2 import Message -from oidcmsg.oauth2 import ResponseMessage +from oidcmsg.oauth2 import Message, ResponseMessage from oidcmsg.oidc import session from oidcservice.service import Service diff --git a/src/oidcservice/oidc/check_session.py b/src/oidcservice/oidc/check_session.py index ad970bd..e29ebc7 100644 --- a/src/oidcservice/oidc/check_session.py +++ b/src/oidcservice/oidc/check_session.py @@ -1,7 +1,6 @@ import logging -from oidcmsg.oauth2 import Message -from oidcmsg.oauth2 import ResponseMessage +from oidcmsg.oauth2 import Message, ResponseMessage from oidcmsg.oidc import session from oidcservice.service import Service diff --git a/src/oidcservice/oidc/end_session.py b/src/oidcservice/oidc/end_session.py index 8ddfaf8..f8ff8ef 100644 --- a/src/oidcservice/oidc/end_session.py +++ b/src/oidcservice/oidc/end_session.py @@ -1,7 +1,6 @@ import logging -from oidcmsg.oauth2 import Message -from oidcmsg.oauth2 import ResponseMessage +from oidcmsg.oauth2 import Message, ResponseMessage from oidcmsg.oidc import session from oidcservice import rndstr diff --git a/src/oidcservice/oidc/provider_info_discovery.py b/src/oidcservice/oidc/provider_info_discovery.py index 721e273..ace4da9 100644 --- a/src/oidcservice/oidc/provider_info_discovery.py +++ b/src/oidcservice/oidc/provider_info_discovery.py @@ -3,8 +3,8 @@ from oidcmsg import oidc from oidcmsg.oauth2 import ResponseMessage -from oidcservice.oauth2 import provider_info_discovery from oidcservice.exception import ConfigurationError +from oidcservice.oauth2 import provider_info_discovery __author__ = 'Roland Hedberg' diff --git a/src/oidcservice/oidc/read_registration.py b/src/oidcservice/oidc/read_registration.py index fde81a0..1fbfb8f 100644 --- a/src/oidcservice/oidc/read_registration.py +++ b/src/oidcservice/oidc/read_registration.py @@ -6,7 +6,6 @@ from oidcservice.service import Service - LOGGER = logging.getLogger(__name__) diff --git a/src/oidcservice/oidc/userinfo.py b/src/oidcservice/oidc/userinfo.py index 3773df5..f4f4e9f 100644 --- a/src/oidcservice/oidc/userinfo.py +++ b/src/oidcservice/oidc/userinfo.py @@ -7,7 +7,6 @@ from oidcservice.oauth2.utils import get_state_parameter from oidcservice.service import Service - logger = logging.getLogger(__name__) UI2REG = { diff --git a/src/oidcservice/oidc/webfinger.py b/src/oidcservice/oidc/webfinger.py index 94ba2f4..1717a3c 100644 --- a/src/oidcservice/oidc/webfinger.py +++ b/src/oidcservice/oidc/webfinger.py @@ -1,15 +1,12 @@ import logging -from urllib.parse import urlsplit -from urllib.parse import urlunsplit +from urllib.parse import urlsplit, urlunsplit from oidcmsg import oidc from oidcmsg.exception import MissingRequiredAttribute -from oidcmsg.oauth2 import Message -from oidcmsg.oauth2 import ResponseMessage +from oidcmsg.oauth2 import Message, ResponseMessage from oidcmsg.oidc import JRD -from oidcservice.oidc import OIC_ISSUER -from oidcservice.oidc import WF_URL +from oidcservice.oidc import OIC_ISSUER, WF_URL from oidcservice.service import Service __author__ = 'Roland Hedberg' diff --git a/src/oidcservice/service.py b/src/oidcservice/service.py index b2bf0cc..e53684c 100644 --- a/src/oidcservice/service.py +++ b/src/oidcservice/service.py @@ -4,18 +4,14 @@ from cryptojwt.jwt import JWT from oidcmsg.message import Message -from oidcmsg.oauth2 import ResponseMessage -from oidcmsg.oauth2 import is_error_message +from oidcmsg.oauth2 import ResponseMessage, is_error_message from oidcservice import util from oidcservice.client_auth import factory as ca_factory from oidcservice.exception import ResponseError from oidcservice.state_interface import StateInterface -from oidcservice.util import JOSE_ENCODED -from oidcservice.util import JSON_ENCODED -from oidcservice.util import URL_ENCODED -from oidcservice.util import get_http_body -from oidcservice.util import get_http_url +from oidcservice.util import (JOSE_ENCODED, JSON_ENCODED, URL_ENCODED, + get_http_body, get_http_url) __author__ = 'Roland Hedberg' @@ -393,12 +389,15 @@ def gather_verify_arguments(self): """ kwargs = { - 'client_id': self.service_context.get('client_id'), 'iss': self.service_context.get('issuer'), 'keyjar': self.service_context.keyjar, 'verify': True } + _client_id = self.service_context.get('client_id') + if _client_id: + kwargs['client_id'] = _client_id + if self.service_name == "provider_info": if self.service_context.get('issuer').startswith("http://"): kwargs["allow_http"] = True diff --git a/src/oidcservice/service_context.py b/src/oidcservice/service_context.py index 64a317e..dc58b9b 100644 --- a/src/oidcservice/service_context.py +++ b/src/oidcservice/service_context.py @@ -6,17 +6,15 @@ import hashlib import os -from cryptojwt.jwk.rsa import RSAKey -from cryptojwt.jwk.rsa import import_private_rsa_key_from_file +from cryptojwt.jwk.rsa import RSAKey, import_private_rsa_key_from_file from cryptojwt.key_bundle import KeyBundle from cryptojwt.key_jar import build_keyjar from cryptojwt.utils import as_bytes +from oidcmsg.context import OidcContext # This represents a map between the local storage of algorithm choices # and how they are represented in a provider info response. from oidcmsg.message import Message from oidcmsg.oidc import RegistrationRequest -from oidcmsg.context import OidcContext - CLI_REG_MAP = { "userinfo": { diff --git a/src/oidcservice/state_interface.py b/src/oidcservice/state_interface.py index 45d810c..802cb42 100644 --- a/src/oidcservice/state_interface.py +++ b/src/oidcservice/state_interface.py @@ -1,9 +1,8 @@ """A database interface for storing state information.""" import json -from oidcmsg.message import Message -from oidcmsg.message import SINGLE_OPTIONAL_JSON -from oidcmsg.message import SINGLE_REQUIRED_STRING +from oidcmsg.message import (SINGLE_OPTIONAL_JSON, SINGLE_REQUIRED_STRING, + Message) from oidcmsg.oidc import verified_claim_name from oidcservice import rndstr diff --git a/src/oidcservice/util.py b/src/oidcservice/util.py index 45551fe..2f0243a 100755 --- a/src/oidcservice/util.py +++ b/src/oidcservice/util.py @@ -1,9 +1,7 @@ """Utilities""" import importlib import logging -from urllib.parse import parse_qs -from urllib.parse import urlsplit -from urllib.parse import urlunsplit +from urllib.parse import parse_qs, urlsplit, urlunsplit import yaml from oidcmsg.exception import UnSupported diff --git a/tests/test_03_util.py b/tests/test_03_util.py index ccccbaa..f03cb53 100644 --- a/tests/test_03_util.py +++ b/tests/test_03_util.py @@ -1,13 +1,10 @@ import json -from urllib.parse import parse_qs -from urllib.parse import urlsplit +from urllib.parse import parse_qs, urlsplit -from oidcmsg.oauth2 import AccessTokenRequest -from oidcmsg.oauth2 import AuthorizationRequest +from oidcmsg.oauth2 import AccessTokenRequest, AuthorizationRequest from oidcservice import util -from oidcservice.util import JSON_ENCODED -from oidcservice.util import URL_ENCODED +from oidcservice.util import JSON_ENCODED, URL_ENCODED __author__ = 'Roland Hedberg' diff --git a/tests/test_07_service.py b/tests/test_07_service.py index 263cd12..837645a 100644 --- a/tests/test_07_service.py +++ b/tests/test_07_service.py @@ -1,14 +1,10 @@ import pytest +from oidcmsg.oauth2 import (SINGLE_OPTIONAL_INT, SINGLE_OPTIONAL_STRING, + SINGLE_REQUIRED_STRING, Message) -from oidcservice.service_context import ServiceContext from oidcservice.service import Service -from oidcservice.state_interface import InMemoryStateDataBase -from oidcservice.state_interface import State - -from oidcmsg.oauth2 import Message -from oidcmsg.oauth2 import SINGLE_OPTIONAL_INT -from oidcmsg.oauth2 import SINGLE_OPTIONAL_STRING -from oidcmsg.oauth2 import SINGLE_REQUIRED_STRING +from oidcservice.service_context import ServiceContext +from oidcservice.state_interface import InMemoryStateDataBase, State class DummyMessage(Message): diff --git a/tests/test_08_webfinger.py b/tests/test_08_webfinger.py index ebef5d8..e20842b 100644 --- a/tests/test_08_webfinger.py +++ b/tests/test_08_webfinger.py @@ -1,12 +1,9 @@ import json -from urllib.parse import parse_qs -from urllib.parse import unquote_plus -from urllib.parse import urlsplit +from urllib.parse import parse_qs, unquote_plus, urlsplit import pytest from oidcmsg.exception import MissingRequiredAttribute -from oidcmsg.oidc import JRD -from oidcmsg.oidc import Link +from oidcmsg.oidc import JRD, Link from oidcservice.oidc import OIC_ISSUER from oidcservice.oidc.webfinger import WebFinger diff --git a/tests/test_09_client_auth.py b/tests/test_09_client_auth.py index 303e865..c2a40f7 100755 --- a/tests/test_09_client_auth.py +++ b/tests/test_09_client_auth.py @@ -3,35 +3,25 @@ from urllib.parse import quote_plus import pytest - -from cryptojwt.key_bundle import KeyBundle -from cryptojwt.key_jar import KeyJar from cryptojwt.jws.jws import JWS from cryptojwt.jwt import JWT +from cryptojwt.key_bundle import KeyBundle +from cryptojwt.key_jar import KeyJar from oidcmsg.message import Message +from oidcmsg.oauth2 import (AccessTokenRequest, AccessTokenResponse, + AuthorizationRequest, AuthorizationResponse, + CCAccessTokenRequest, ResourceRequest) from oidcservice import JWT_BEARER -from oidcservice.client_auth import assertion_jwt -from oidcservice.client_auth import BearerBody -from oidcservice.client_auth import BearerHeader -from oidcservice.client_auth import ClientSecretBasic -from oidcservice.client_auth import ClientSecretJWT -from oidcservice.client_auth import ClientSecretPost -from oidcservice.client_auth import PrivateKeyJWT -from oidcservice.client_auth import valid_service_context +from oidcservice.client_auth import (BearerBody, BearerHeader, + ClientSecretBasic, ClientSecretJWT, + ClientSecretPost, PrivateKeyJWT, + assertion_jwt, valid_service_context) from oidcservice.oidc import DEFAULT_SERVICES -from oidcservice.service_factory import service_factory from oidcservice.service import init_services from oidcservice.service_context import ServiceContext -from oidcservice.state_interface import InMemoryStateDataBase -from oidcservice.state_interface import State - -from oidcmsg.oauth2 import AccessTokenRequest -from oidcmsg.oauth2 import AccessTokenResponse -from oidcmsg.oauth2 import AuthorizationRequest -from oidcmsg.oauth2 import AuthorizationResponse -from oidcmsg.oauth2 import CCAccessTokenRequest -from oidcmsg.oauth2 import ResourceRequest +from oidcservice.service_factory import service_factory +from oidcservice.state_interface import InMemoryStateDataBase, State BASE_PATH = os.path.abspath(os.path.dirname(__file__)) CLIENT_ID = "A" @@ -269,12 +259,13 @@ def test_construct(self, services): _service.service_context.set('provider_info', { 'issuer': 'https://example.com/', 'token_endpoint': "https://example.com/token"}) + _service.service_context.set("registration_response", { + 'token_endpoint_auth_signing_alg': 'RS256'}) services['accesstoken'].endpoint = "https://example.com/token" request = AccessTokenRequest() pkj = PrivateKeyJWT() - http_args = pkj.construct(request, service=_service, algorithm="RS256", - authn_endpoint='token_endpoint') + http_args = pkj.construct(request, service=_service, authn_endpoint='token_endpoint') assert http_args == {} cas = request["client_assertion"] @@ -307,15 +298,18 @@ class TestClientSecretJWT_TE(object): def test_client_secret_jwt(self, services): _service_context = services['accesstoken'].service_context _service_context.token_endpoint = "https://example.com/token" + _service_context.set('provider_info', { 'issuer': 'https://example.com/', 'token_endpoint': "https://example.com/token"}) + _service_context.set("registration_response", { + 'token_endpoint_auth_signing_alg': "HS256"}) + csj = ClientSecretJWT() request = AccessTokenRequest() - csj.construct(request, service=services['accesstoken'], - algorithm="HS256", authn_endpoint='token_endpoint') + csj.construct(request, service=services['accesstoken'], authn_endpoint='token_endpoint') assert request["client_assertion_type"] == JWT_BEARER assert "client_assertion" in request cas = request["client_assertion"] diff --git a/tests/test_10_oauth2_service.py b/tests/test_10_oauth2_service.py index 8fdeee6..fc726d2 100644 --- a/tests/test_10_oauth2_service.py +++ b/tests/test_10_oauth2_service.py @@ -1,15 +1,12 @@ import pytest -from oidcmsg.oauth2 import AccessTokenRequest -from oidcmsg.oauth2 import AccessTokenResponse -from oidcmsg.oauth2 import AuthorizationRequest -from oidcmsg.oauth2 import AuthorizationResponse -from oidcmsg.oauth2 import Message +from oidcmsg.oauth2 import (AccessTokenRequest, AccessTokenResponse, + AuthorizationRequest, AuthorizationResponse, + Message) from oidcservice.service import Service from oidcservice.service_context import ServiceContext from oidcservice.service_factory import service_factory -from oidcservice.state_interface import InMemoryStateDataBase -from oidcservice.state_interface import State +from oidcservice.state_interface import InMemoryStateDataBase, State class Response(object): diff --git a/tests/test_13_oic_service.py b/tests/test_13_oic_service.py index 6b43b2c..7094cea 100644 --- a/tests/test_13_oic_service.py +++ b/tests/test_13_oic_service.py @@ -6,24 +6,18 @@ from cryptojwt.jws import jws from cryptojwt.jws.utils import left_hash from cryptojwt.jwt import JWT -from cryptojwt.key_jar import build_keyjar -from cryptojwt.key_jar import init_key_jar -from oidcmsg.oauth2 import AccessTokenRequest -from oidcmsg.oauth2 import AccessTokenResponse -from oidcmsg.oauth2 import AuthorizationRequest -from oidcmsg.oauth2 import AuthorizationResponse -from oidcmsg.oauth2 import Message -from oidcmsg.oidc import IdToken -from oidcmsg.oidc import OpenIDSchema -from oidcmsg.oidc import RegistrationRequest -from oidcmsg.oidc import verified_claim_name -from oidcmsg.oidc.session import CheckIDRequest -from oidcmsg.oidc.session import CheckSessionRequest -from oidcmsg.oidc.session import EndSessionRequest +from cryptojwt.key_jar import build_keyjar, init_key_jar +from oidcmsg.oauth2 import (AccessTokenRequest, AccessTokenResponse, + AuthorizationRequest, AuthorizationResponse, + Message) +from oidcmsg.oidc import (IdToken, OpenIDSchema, RegistrationRequest, + verified_claim_name) +from oidcmsg.oidc.session import (CheckIDRequest, CheckSessionRequest, + EndSessionRequest) from oidcservice.exception import ParameterError -from oidcservice.oidc.registration import add_jwks_uri_or_jwks -from oidcservice.oidc.registration import response_types_to_grant_types +from oidcservice.oidc.registration import (add_jwks_uri_or_jwks, + response_types_to_grant_types) from oidcservice.service_context import ServiceContext from oidcservice.service_factory import service_factory diff --git a/tests/test_14_pkce.py b/tests/test_14_pkce.py index 09dd428..2f864ee 100644 --- a/tests/test_14_pkce.py +++ b/tests/test_14_pkce.py @@ -2,20 +2,16 @@ import pytest from cryptojwt.key_jar import init_key_jar -from oidcmsg.message import Message -from oidcmsg.message import SINGLE_REQUIRED_STRING +from oidcmsg.message import SINGLE_REQUIRED_STRING, Message from oidcmsg.oauth2 import AuthorizationResponse from oidcservice.client_auth import factory as ca_factory from oidcservice.oauth2 import DEFAULT_SERVICES from oidcservice.oidc.add_on import do_add_ons -from oidcservice.oidc.add_on.pkce import add_code_challenge -from oidcservice.oidc.add_on.pkce import add_code_verifier -from oidcservice.service import Service -from oidcservice.service import init_services +from oidcservice.oidc.add_on.pkce import add_code_challenge, add_code_verifier +from oidcservice.service import Service, init_services from oidcservice.service_context import ServiceContext -from oidcservice.state_interface import InMemoryStateDataBase -from oidcservice.state_interface import State +from oidcservice.state_interface import InMemoryStateDataBase, State class DummyMessage(Message): diff --git a/tests/test_15_oic_utils.py b/tests/test_15_oic_utils.py index b3fc5d4..09c2b4f 100644 --- a/tests/test_15_oic_utils.py +++ b/tests/test_15_oic_utils.py @@ -1,10 +1,10 @@ -from oidcservice.service_context import ServiceContext +from cryptojwt.jwe.jwe import factory +from cryptojwt.key_jar import build_keyjar from oidcmsg.oidc import AuthorizationRequest -from oidcservice.oidc.utils import construct_request_uri -from oidcservice.oidc.utils import request_object_encryption -from cryptojwt.key_jar import build_keyjar -from cryptojwt.jwe.jwe import factory +from oidcservice.oidc.utils import (construct_request_uri, + request_object_encryption) +from oidcservice.service_context import ServiceContext KEYSPEC = [ {"type": "RSA", "use": ["enc"]}, diff --git a/tests/test_16_cc_oauth2_service.py b/tests/test_16_cc_oauth2_service.py index 8bcfdaa..9eb8716 100644 --- a/tests/test_16_cc_oauth2_service.py +++ b/tests/test_16_cc_oauth2_service.py @@ -1,7 +1,7 @@ import pytest -from oidcservice.service_factory import service_factory from oidcservice.service_context import ServiceContext +from oidcservice.service_factory import service_factory from oidcservice.state_interface import InMemoryStateDataBase KEYDEF = [{"type": "EC", "crv": "P-256", "use": ["sig"]}] diff --git a/tests/test_17_read_registration.py b/tests/test_17_read_registration.py index 42b14b7..c4d83ce 100644 --- a/tests/test_17_read_registration.py +++ b/tests/test_17_read_registration.py @@ -2,11 +2,11 @@ import time import pytest -import requests import responses from cryptojwt.utils import as_bytes from oidcmsg.oidc import RegistrationResponse +import requests from oidcservice.service_context import ServiceContext from oidcservice.service_factory import service_factory diff --git a/tests/test_20_conversation.py b/tests/test_20_conversation.py index 8a5ca62..a24ffc4 100644 --- a/tests/test_20_conversation.py +++ b/tests/test_20_conversation.py @@ -1,24 +1,18 @@ #!/usr/bin/env python3 import json - import time -from urllib.parse import parse_qs -from urllib.parse import urlparse +from urllib.parse import parse_qs, urlparse from cryptojwt.jwt import JWT from cryptojwt.key_jar import KeyJar +from oidcmsg.oidc import (JRD, AccessTokenResponse, AuthorizationResponse, + Link, OpenIDSchema, ProviderConfigurationResponse, + RegistrationResponse) -from oidcmsg.oidc import AccessTokenResponse, Link -from oidcmsg.oidc import AuthorizationResponse -from oidcmsg.oidc import JRD -from oidcmsg.oidc import OpenIDSchema -from oidcmsg.oidc import ProviderConfigurationResponse -from oidcmsg.oidc import RegistrationResponse +from oidcservice.oidc import DEFAULT_SERVICES from oidcservice.oidc.webfinger import WebFinger - from oidcservice.service import init_services from oidcservice.service_context import ServiceContext -from oidcservice.oidc import DEFAULT_SERVICES from oidcservice.state_interface import InMemoryStateDataBase # ================== SETUP =========================== diff --git a/tests/test_21_pushed_auth.py b/tests/test_21_pushed_auth.py index b2cadf6..2ecc2d1 100644 --- a/tests/test_21_pushed_auth.py +++ b/tests/test_21_pushed_auth.py @@ -40,7 +40,7 @@ def create_client(self): ".add_pushed_authorization_support", "kwargs": { "body_format": "jws", - "signing_algorthm": "RS256", + "signing_algorithm": "RS256", "http_client": None, "merge_rule": "lax" } diff --git a/tests/test_30_persistence.py b/tests/test_30_persistence.py index 79ff88f..891d98e 100644 --- a/tests/test_30_persistence.py +++ b/tests/test_30_persistence.py @@ -2,15 +2,13 @@ import json import shutil import time -from urllib.parse import parse_qs -from urllib.parse import urlparse +from urllib.parse import parse_qs, urlparse import responses from cryptojwt.jwt import JWT from cryptojwt.key_jar import KeyJar -from oidcmsg.oidc import AccessTokenResponse -from oidcmsg.oidc import AuthorizationResponse -from oidcmsg.oidc import OpenIDSchema +from oidcmsg.oidc import (AccessTokenResponse, AuthorizationResponse, + OpenIDSchema) from oidcservice.oidc import DEFAULT_SERVICES from oidcservice.oidc.webfinger import WebFinger @@ -58,7 +56,7 @@ OP_KEYJAR = KeyJar() OP_KEYJAR.import_jwks(JWKS_OP, '') -OP_BASEURL = "https://example.org/op" +OP_BASEURL = "https://example.org" RP_JWKS = { "keys": [{ @@ -113,7 +111,7 @@ def build_service_context() -> object: _service_context = ServiceContext( config={ - "issuer": 'https://op.example.com', + "issuer": OP_BASEURL, "client_preferences": { "application_type": "web", @@ -177,19 +175,19 @@ def test_conversation(): service_2 = service_context_2.service # ======================== WebFinger ======================== - info = service['webfinger'].get_request_parameters( request_args={'resource': 'foobar@example.org'}) - assert info['url'] == 'https://example.org/.well-known/webfinger?rel=http' \ - '%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer' \ - '&resource=acct%3Afoobar%40example.org' + _url = ('{}/.well-known/webfinger?rel=http' + '%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer' + '&resource=acct%3Afoobar%40example.org').format(OP_BASEURL) + assert info['url'] == _url webfinger_response = json.dumps({ "subject": "acct:foobar@example.org", "links": [{ "rel": "http://openid.net/specs/connect/1.0/issuer", - "href": "https://example.org/op" + "href": OP_BASEURL # "https://example.org/op" }], "expires": "2018-02-04T11:08:41Z" }) @@ -202,7 +200,7 @@ def test_conversation(): info = service_context_2.service['provider_info'].get_request_parameters() - assert info['url'] == 'https://example.org/op/.well-known/openid-configuration' + assert info['url'] == '{}/.well-known/openid-configuration'.format(OP_BASEURL) provider_info_response = json.dumps({ "version": "3.0", @@ -302,13 +300,13 @@ def test_conversation(): info = service['registration'].get_request_parameters() - assert info['url'] == 'https://example.org/op/registration' + assert info['url'] == '{}/registration'.format(OP_BASEURL) _body = json.loads(info['body']) assert _body == { "application_type": "web", "response_types": ["code"], "contacts": ["ops@example.org"], - "jwks_uri": "https://example.com/rp/static/jwks.json", + "jwks_uri": "{}/static/jwks.json".format(RP_BASEURL), "redirect_uris": ["{}/authz_cb".format(RP_BASEURL)], 'token_endpoint_auth_method': 'client_secret_basic', "grant_types": ["authorization_code"] @@ -374,11 +372,11 @@ def test_conversation(): info = service['accesstoken'].get_request_parameters( request_args=request_args) - assert info['url'] == 'https://example.org/op/token' + assert info['url'] == '{}/token'.format(OP_BASEURL) _qp = parse_qs(info['body']) assert _qp == { 'grant_type': ['authorization_code'], - 'redirect_uri': ['https://example.com/rp/authz_cb'], + 'redirect_uri': ['{}/authz_cb'.format(RP_BASEURL)], 'client_id': ['zls2qhN1jO6A'], 'state': ['Oh3w3gKlvoM2ehFqlxI3HIK5'], 'code': ['Z0FBQUFBQmFkdFFjUVpFWE81SHU5N1N4N01'] @@ -432,7 +430,7 @@ def test_conversation(): info = service_2['userinfo'].get_request_parameters(state=STATE) - assert info['url'] == 'https://example.org/op/userinfo' + assert info['url'] == '{}/userinfo'.format(OP_BASEURL) assert info['headers'] == {'Authorization': 'Bearer Z0FBQUFBQmFkdFF'} op_resp = {"sub": "1b2fc9341a16ae4e30082965d537"} @@ -442,6 +440,5 @@ def test_conversation(): assert isinstance(_resp, OpenIDSchema) assert _resp.to_dict() == {'sub': '1b2fc9341a16ae4e30082965d537'} - _item = service['authorization'].get_item(OpenIDSchema, 'user_info', STATE) assert _item.to_dict() == {'sub': '1b2fc9341a16ae4e30082965d537'} diff --git a/tox.ini b/tox.ini index 7dedcdd..efcafe0 100755 --- a/tox.ini +++ b/tox.ini @@ -1,31 +1,28 @@ [tox] -envlist = py{27,34,36},docs,quality +envlist = py{36,37,38},docs,quality [testenv] -setenv = - COVERAGE_FILE = {toxinidir}/.coverage.{envname} -passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH +passenv = CI TRAVIS TRAVIS_* commands = - pipenv install --dev - pipenv run py.test --cov-report= --cov=oic tests/ -m "not network" {posargs} - ; Transform absolute path to relative path for compatibility with coveralls.io and fix 'source not available' error. - pipenv run python -c "import os;cov_strip_abspath = open(os.environ['COVERAGE_FILE'], 'r').read().replace('.tox' + os.sep + os.path.relpath('{envsitepackagesdir}', '{toxworkdir}'), 'src');open(os.environ['COVERAGE_FILE'], 'w').write(cov_strip_abspath)" -deps = pipenv + py.test --cov-report= --cov=oidcservice tests/ -m "not network" {posargs} + codecov +extras = testing +deps = + codecov + pytest-cov + responses [testenv:docs] whitelist_externals = make -deps = pipenv -commands = - pipenv install --dev - make html +extras = docs +commands = sphinx-build -b html doc/ doc/_build/html -W [testenv:quality] -whitelist_externals = make -deps = pipenv +ignore_errors = True +extras = quality commands = - pipenv install --dev - make check-isort - make check-pylama + isort --diff --check-only src/ tests/ + pylama src/ tests/ [testenv:coveralls] setenv =